Apply states for projects (active, readonly and hidden)
This feature is the result of the discussion about issue 349 which the project can assume one of the states mentioned above. Active state indicates the project is regular and is the default value. Read Only means that users can see the project if read permission is granted, but all modification operations are disabled. Hidden means the project is not visible for those who are not owners Bug: issue 349 Change-Id: I2a8972701359c3792331712efc93cb6ded2065f5
This commit is contained in:

committed by
Gustaf Lundh

parent
a3b3e95ae7
commit
acbf134d54
@@ -41,6 +41,7 @@ public class ChangeDetail {
|
||||
protected List<ChangeMessage> messages;
|
||||
protected PatchSet.Id currentPatchSetId;
|
||||
protected PatchSetDetail currentDetail;
|
||||
protected boolean canEdit;
|
||||
|
||||
public ChangeDetail() {
|
||||
}
|
||||
@@ -190,4 +191,12 @@ public class ChangeDetail {
|
||||
public String getDescription() {
|
||||
return currentDetail != null ? currentDetail.getInfo().getMessage() : "";
|
||||
}
|
||||
|
||||
public void setCanEdit(boolean a) {
|
||||
canEdit = a;
|
||||
}
|
||||
|
||||
public boolean canEdit() {
|
||||
return canEdit;
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ public class ProjectDetail {
|
||||
public boolean canModifyMergeType;
|
||||
public boolean canModifyAgreements;
|
||||
public boolean canModifyAccess;
|
||||
public boolean canModifyState;
|
||||
|
||||
public ProjectDetail() {
|
||||
}
|
||||
@@ -38,6 +39,10 @@ public class ProjectDetail {
|
||||
canModifyMergeType = cmmt;
|
||||
}
|
||||
|
||||
public void setCanModifyState(final boolean cms) {
|
||||
canModifyState = cms;
|
||||
}
|
||||
|
||||
public void setCanModifyAgreements(final boolean cma) {
|
||||
canModifyAgreements = cma;
|
||||
}
|
||||
|
@@ -63,6 +63,10 @@ public interface AdminConstants extends Constants {
|
||||
String projectSubmitType_MERGE_IF_NECESSARY();
|
||||
String projectSubmitType_CHERRY_PICK();
|
||||
|
||||
String projectState_ACTIVE();
|
||||
String projectState_READ_ONLY();
|
||||
String projectState_HIDDEN();
|
||||
|
||||
String groupType_SYSTEM();
|
||||
String groupType_INTERNAL();
|
||||
String groupType_LDAP();
|
||||
|
@@ -43,6 +43,10 @@ projectSubmitType_MERGE_IF_NECESSARY = Merge If Necessary
|
||||
projectSubmitType_MERGE_ALWAYS = Always Merge
|
||||
projectSubmitType_CHERRY_PICK = Cherry Pick
|
||||
|
||||
projectState_ACTIVE = Active
|
||||
projectState_READ_ONLY = Read Only
|
||||
projectState_HIDDEN = Hidden
|
||||
|
||||
groupType_SYSTEM = System Group
|
||||
groupType_INTERNAL = Internal Group
|
||||
groupType_LDAP = LDAP Group
|
||||
|
@@ -39,6 +39,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
private Panel projectOptionsPanel;
|
||||
private CheckBox requireChangeID;
|
||||
private ListBox submitType;
|
||||
private ListBox state;
|
||||
private CheckBox useContentMerge;
|
||||
|
||||
private Panel agreementsPanel;
|
||||
@@ -79,19 +80,22 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
new ScreenLoadCallback<ProjectDetail>(this) {
|
||||
public void preDisplay(final ProjectDetail result) {
|
||||
enableForm(result.canModifyAgreements,
|
||||
result.canModifyDescription, result.canModifyMergeType);
|
||||
result.canModifyDescription, result.canModifyMergeType, result.canModifyState);
|
||||
saveProject.setVisible(
|
||||
result.canModifyAgreements ||
|
||||
result.canModifyDescription ||
|
||||
result.canModifyMergeType);
|
||||
result.canModifyMergeType ||
|
||||
result.canModifyState);
|
||||
display(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void enableForm(final boolean canModifyAgreements,
|
||||
final boolean canModifyDescription, final boolean canModifyMergeType) {
|
||||
final boolean canModifyDescription, final boolean canModifyMergeType,
|
||||
final boolean canModifyState) {
|
||||
submitType.setEnabled(canModifyMergeType);
|
||||
state.setEnabled(canModifyState);
|
||||
useContentMerge.setEnabled(canModifyMergeType);
|
||||
descTxt.setEnabled(canModifyDescription);
|
||||
useContributorAgreements.setEnabled(canModifyAgreements);
|
||||
@@ -130,6 +134,14 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
saveEnabler.listenTo(submitType);
|
||||
projectOptionsPanel.add(submitType);
|
||||
|
||||
state = new ListBox();
|
||||
for (final Project.State stateValue : Project.State.values()) {
|
||||
state.addItem(Util.toLongString(stateValue), stateValue.name());
|
||||
}
|
||||
|
||||
saveEnabler.listenTo(state);
|
||||
projectOptionsPanel.add(state);
|
||||
|
||||
useContentMerge = new CheckBox(Util.C.useContentMerge(), true);
|
||||
saveEnabler.listenTo(useContentMerge);
|
||||
projectOptionsPanel.add(useContentMerge);
|
||||
@@ -186,6 +198,17 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
}
|
||||
}
|
||||
|
||||
private void setState(final Project.State newState) {
|
||||
if (state != null) {
|
||||
for (int i = 0; i < state.getItemCount(); i++) {
|
||||
if (newState.name().equals(state.getValue(i))) {
|
||||
state.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display(final ProjectDetail result) {
|
||||
project = result.project;
|
||||
|
||||
@@ -202,6 +225,7 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
useContentMerge.setValue(project.isUseContentMerge());
|
||||
requireChangeID.setValue(project.isRequireChangeID());
|
||||
setSubmitType(project.getSubmitType());
|
||||
setState(project.getState());
|
||||
|
||||
saveProject.setEnabled(false);
|
||||
}
|
||||
@@ -216,14 +240,18 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
project.setSubmitType(Project.SubmitType.valueOf(submitType
|
||||
.getValue(submitType.getSelectedIndex())));
|
||||
}
|
||||
if (state.getSelectedIndex() >= 0) {
|
||||
project.setState(Project.State.valueOf(state
|
||||
.getValue(state.getSelectedIndex())));
|
||||
}
|
||||
|
||||
enableForm(false, false, false);
|
||||
enableForm(false, false, false, false);
|
||||
|
||||
Util.PROJECT_SVC.changeProjectSettings(project,
|
||||
new GerritCallback<ProjectDetail>() {
|
||||
public void onSuccess(final ProjectDetail result) {
|
||||
enableForm(result.canModifyAgreements,
|
||||
result.canModifyDescription, result.canModifyMergeType);
|
||||
result.canModifyDescription, result.canModifyMergeType, result.canModifyState);
|
||||
display(result);
|
||||
}
|
||||
});
|
||||
|
@@ -53,4 +53,20 @@ public class Util {
|
||||
return type.name();
|
||||
}
|
||||
}
|
||||
|
||||
public static String toLongString(final Project.State type) {
|
||||
if (type == null) {
|
||||
return "";
|
||||
}
|
||||
switch (type) {
|
||||
case ACTIVE:
|
||||
return C.projectState_ACTIVE();
|
||||
case READ_ONLY:
|
||||
return C.projectState_READ_ONLY();
|
||||
case HIDDEN:
|
||||
return C.projectState_HIDDEN();
|
||||
default:
|
||||
return type.name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -164,9 +164,11 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
|
||||
actionsPanel.setStyleName(Gerrit.RESOURCES.css().patchSetActions());
|
||||
body.add(actionsPanel);
|
||||
if (Gerrit.isSignedIn()) {
|
||||
populateReviewAction();
|
||||
if (changeDetail.isCurrentPatchSet(detail)) {
|
||||
populateActions(detail);
|
||||
if (changeDetail.canEdit()) {
|
||||
populateReviewAction();
|
||||
if (changeDetail.isCurrentPatchSet(detail)) {
|
||||
populateActions(detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
populateDiffAllActions(detail);
|
||||
|
@@ -125,6 +125,8 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
|
||||
|
||||
detail.setCanRevert(change.getStatus() == Change.Status.MERGED && control.canAddPatchSet());
|
||||
|
||||
detail.setCanEdit(control.getRefControl().canWrite());
|
||||
|
||||
if (detail.getChange().getStatus().isOpen()) {
|
||||
List<SubmitRecord> submitRecords = control.canSubmit(db, patch.getId());
|
||||
for (SubmitRecord rec : submitRecords) {
|
||||
|
@@ -57,6 +57,7 @@ class ProjectDetailFactory extends Handler<ProjectDetail> {
|
||||
detail.setCanModifyAgreements(userIsOwner);
|
||||
detail.setCanModifyDescription(userIsOwner);
|
||||
detail.setCanModifyMergeType(userIsOwner);
|
||||
detail.setCanModifyState(userIsOwner);
|
||||
return detail;
|
||||
}
|
||||
}
|
||||
|
@@ -75,6 +75,14 @@ public final class Project {
|
||||
CHERRY_PICK;
|
||||
}
|
||||
|
||||
public static enum State {
|
||||
ACTIVE,
|
||||
|
||||
READ_ONLY,
|
||||
|
||||
HIDDEN;
|
||||
}
|
||||
|
||||
protected NameKey name;
|
||||
|
||||
protected String description;
|
||||
@@ -85,6 +93,8 @@ public final class Project {
|
||||
|
||||
protected SubmitType submitType;
|
||||
|
||||
protected State state;
|
||||
|
||||
protected NameKey parent;
|
||||
|
||||
protected boolean requireChangeID;
|
||||
@@ -97,6 +107,7 @@ public final class Project {
|
||||
public Project(Project.NameKey nameKey) {
|
||||
name = nameKey;
|
||||
submitType = SubmitType.MERGE_IF_NECESSARY;
|
||||
state = State.ACTIVE;
|
||||
}
|
||||
|
||||
public Project.NameKey getNameKey() {
|
||||
@@ -155,6 +166,14 @@ public final class Project {
|
||||
submitType = type;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(final State newState) {
|
||||
state = newState;
|
||||
}
|
||||
|
||||
public void copySettingsFrom(final Project update) {
|
||||
description = update.description;
|
||||
useContributorAgreements = update.useContributorAgreements;
|
||||
@@ -162,6 +181,7 @@ public final class Project {
|
||||
useContentMerge = update.useContentMerge;
|
||||
requireChangeID = update.requireChangeID;
|
||||
submitType = update.submitType;
|
||||
state = update.state;
|
||||
}
|
||||
|
||||
public Project.NameKey getParent() {
|
||||
|
@@ -24,6 +24,7 @@ import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.Project.State;
|
||||
import com.google.gerrit.reviewdb.Project.SubmitType;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
|
||||
@@ -66,9 +67,12 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private static final String SUBMIT = "submit";
|
||||
private static final String KEY_ACTION = "action";
|
||||
private static final String KEY_MERGE_CONTENT = "mergeContent";
|
||||
private static final String KEY_STATE = "state";
|
||||
|
||||
private static final SubmitType defaultSubmitAction =
|
||||
SubmitType.MERGE_IF_NECESSARY;
|
||||
private static final State defaultStateValue =
|
||||
State.ACTIVE;
|
||||
|
||||
private Project.NameKey projectName;
|
||||
private Project project;
|
||||
@@ -217,6 +221,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
|
||||
p.setSubmitType(getEnum(rc, SUBMIT, null, KEY_ACTION, defaultSubmitAction));
|
||||
p.setUseContentMerge(getBoolean(rc, SUBMIT, KEY_MERGE_CONTENT, false));
|
||||
p.setState(getEnum(rc, PROJECT, null, KEY_STATE, defaultStateValue));
|
||||
|
||||
accessSections = new HashMap<String, AccessSection>();
|
||||
for (String refName : rc.getSubsections(ACCESS)) {
|
||||
@@ -341,6 +346,8 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);
|
||||
set(rc, SUBMIT, null, KEY_MERGE_CONTENT, p.isUseContentMerge());
|
||||
|
||||
set(rc, PROJECT, null, KEY_STATE, p.getState(), null);
|
||||
|
||||
Set<AccountGroup.UUID> keepGroups = new HashSet<AccountGroup.UUID>();
|
||||
AccessSection capability = accessSections.get(AccessSection.GLOBAL_CAPABILITIES);
|
||||
if (capability != null) {
|
||||
|
@@ -192,10 +192,14 @@ public class ProjectControl {
|
||||
return state.getProject();
|
||||
}
|
||||
|
||||
private boolean isHidden() {
|
||||
return getProject().getState().equals(Project.State.HIDDEN);
|
||||
}
|
||||
|
||||
/** Can this user see this project exists? */
|
||||
public boolean isVisible() {
|
||||
return visibleForReplication()
|
||||
|| canPerformOnAnyRef(Permission.READ);
|
||||
return (visibleForReplication()
|
||||
|| canPerformOnAnyRef(Permission.READ)) && !isHidden();
|
||||
}
|
||||
|
||||
public boolean canAddRefs() {
|
||||
|
@@ -18,6 +18,7 @@ import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRange;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
@@ -97,8 +98,8 @@ public class RefControl {
|
||||
|
||||
/** Can this user see this reference exists? */
|
||||
public boolean isVisible() {
|
||||
return projectControl.visibleForReplication()
|
||||
|| canPerform(Permission.READ);
|
||||
return (projectControl.visibleForReplication() || canPerform(Permission.READ))
|
||||
&& canRead();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,16 +110,16 @@ public class RefControl {
|
||||
* ref
|
||||
*/
|
||||
public boolean canUpload() {
|
||||
return projectControl
|
||||
.controlForRef("refs/for/" + getRefName())
|
||||
.canPerform(Permission.PUSH);
|
||||
return projectControl.controlForRef("refs/for/" + getRefName())
|
||||
.canPerform(Permission.PUSH)
|
||||
&& canWrite();
|
||||
}
|
||||
|
||||
/** @return true if this user can submit merge patch sets to this ref */
|
||||
public boolean canUploadMerges() {
|
||||
return projectControl
|
||||
.controlForRef("refs/for/" + getRefName())
|
||||
.canPerform(Permission.PUSH_MERGE);
|
||||
return projectControl.controlForRef("refs/for/" + getRefName())
|
||||
.canPerform(Permission.PUSH_MERGE)
|
||||
&& canWrite();
|
||||
}
|
||||
|
||||
/** @return true if this user can submit patch sets to this ref */
|
||||
@@ -131,7 +132,8 @@ public class RefControl {
|
||||
// granting of powers beyond submitting to the configuration.
|
||||
return projectControl.isOwner();
|
||||
}
|
||||
return canPerform(Permission.SUBMIT);
|
||||
return canPerform(Permission.SUBMIT)
|
||||
&& canWrite();
|
||||
}
|
||||
|
||||
/** @return true if the user can update the reference as a fast-forward. */
|
||||
@@ -145,17 +147,28 @@ public class RefControl {
|
||||
// granting of powers beyond pushing to the configuration.
|
||||
return false;
|
||||
}
|
||||
return canPerform(Permission.PUSH);
|
||||
return canPerform(Permission.PUSH)
|
||||
&& canWrite();
|
||||
}
|
||||
|
||||
/** @return true if the user can rewind (force push) the reference. */
|
||||
public boolean canForceUpdate() {
|
||||
return canPushWithForce() || canDelete();
|
||||
return (canPushWithForce() || canDelete()) && canWrite();
|
||||
}
|
||||
|
||||
public boolean canWrite() {
|
||||
return getProjectControl().getProject().getState().equals(
|
||||
Project.State.ACTIVE);
|
||||
}
|
||||
|
||||
public boolean canRead() {
|
||||
return getProjectControl().getProject().getState().equals(
|
||||
Project.State.READ_ONLY) || canWrite();
|
||||
}
|
||||
|
||||
private boolean canPushWithForce() {
|
||||
if (GitRepositoryManager.REF_CONFIG.equals(refName)
|
||||
&& !projectControl.isOwner()) {
|
||||
if (!canWrite() || (GitRepositoryManager.REF_CONFIG.equals(refName)
|
||||
&& !projectControl.isOwner())) {
|
||||
// Pushing requires being at least project owner, in addition to push.
|
||||
// Pushing configuration changes modifies the access control
|
||||
// rules. Allowing this to be done by a non-project-owner opens
|
||||
@@ -183,6 +196,9 @@ public class RefControl {
|
||||
* @return {@code true} if the user specified can create a new Git ref
|
||||
*/
|
||||
public boolean canCreate(RevWalk rw, RevObject object) {
|
||||
if (!canWrite()) {
|
||||
return false;
|
||||
}
|
||||
boolean owner;
|
||||
switch (getCurrentUser().getAccessPath()) {
|
||||
case WEB_UI:
|
||||
@@ -242,7 +258,7 @@ public class RefControl {
|
||||
* @return {@code true} if the user specified can delete a Git ref.
|
||||
*/
|
||||
public boolean canDelete() {
|
||||
if (GitRepositoryManager.REF_CONFIG.equals(refName)) {
|
||||
if (!canWrite() || (GitRepositoryManager.REF_CONFIG.equals(refName))) {
|
||||
// Never allow removal of the refs/meta/config branch.
|
||||
// Deleting the branch would destroy all Gerrit specific
|
||||
// metadata about the project, including its access rules.
|
||||
|
@@ -113,7 +113,9 @@ public class ProjectConfigTest extends LocalDiskRepositoryTestCase {
|
||||
+ " submit = group Developers\n" //
|
||||
+ "\tsubmit = group Staff\n" //
|
||||
+ " upload = group Developers\n" //
|
||||
+ " read = group Developers\n", text(rev, "project.config"));
|
||||
+ " read = group Developers\n"//
|
||||
+ "[project]\n"//
|
||||
+ "\tstate = active\n", text(rev, "project.config"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,7 +142,9 @@ public class ProjectConfigTest extends LocalDiskRepositoryTestCase {
|
||||
+ " submit = group People Who Can Submit\n" //
|
||||
+ "\tsubmit = group Staff\n" //
|
||||
+ " upload = group Developers\n" //
|
||||
+ " read = group Developers\n", text(rev, "project.config"));
|
||||
+ " read = group Developers\n"//
|
||||
+ "[project]\n"//
|
||||
+ "\tstate = active\n", text(rev, "project.config"));
|
||||
}
|
||||
|
||||
private ProjectConfig read(RevCommit rev) throws IOException,
|
||||
|
Reference in New Issue
Block a user