Allow updating the parent project from the WebUI
This change adds support for updating the parent project of a child project from the WebUI. This functionality is offered in the ProjectAccessScreen. When the access rights are changed the user is also able to change the parent project (if the user has the needed privileges, means if he is administrator). When the user saves the new settings only one RPC to the server is done that updates both the access rights and the parent project property. Technically both updates are modifications of the 'project.config' file in the 'refs/meta/config' branch. There will be only one commit for this file that does both updates. In the UI only valid parent projects are suggested as new parent project (all projects that would cause a cycle in the line of parent projects are not suggested). Bug: issue 1298 Change-Id: Ic63bdb039ea5057a0551138f8fef9ede280b2be3 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -28,6 +28,7 @@ public class ProjectAccess {
|
||||
protected Set<String> ownerOf;
|
||||
protected boolean isConfigVisible;
|
||||
protected boolean canUpload;
|
||||
protected boolean canChangeParent;
|
||||
protected LabelTypes labelTypes;
|
||||
protected Map<String, String> capabilities;
|
||||
|
||||
@@ -107,6 +108,14 @@ public class ProjectAccess {
|
||||
this.canUpload = canUpload;
|
||||
}
|
||||
|
||||
public boolean canChangeParent() {
|
||||
return canChangeParent;
|
||||
}
|
||||
|
||||
public void setCanChangeParent(boolean canChangeParent) {
|
||||
this.canChangeParent = canChangeParent;
|
||||
}
|
||||
|
||||
public LabelTypes getLabelTypes() {
|
||||
return labelTypes;
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ public interface ProjectAdminService extends RemoteJsonService {
|
||||
@Audit
|
||||
@SignInRequired
|
||||
void changeProjectAccess(Project.NameKey projectName, String baseRevision,
|
||||
String message, List<AccessSection> sections,
|
||||
String message, List<AccessSection> sections, Project.NameKey parentProjectName,
|
||||
AsyncCallback<ProjectAccess> callback);
|
||||
|
||||
@SignInRequired
|
||||
void reviewProjectAccess(Project.NameKey projectName, String baseRevision,
|
||||
String message, List<AccessSection> sections,
|
||||
String message, List<AccessSection> sections, Project.NameKey parentProjectName,
|
||||
AsyncCallback<Change.Id> callback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2013 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.errors;
|
||||
|
||||
/** Error indicating that updating a parent project failed. */
|
||||
public class UpdateParentFailedException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String MESSAGE = "Update Parent Project Failed: ";
|
||||
|
||||
public UpdateParentFailedException(final String message,
|
||||
final Throwable why) {
|
||||
super(MESSAGE + ": " + message, why);
|
||||
}
|
||||
}
|
||||
@@ -34,4 +34,6 @@ public interface GerritMessages extends Messages {
|
||||
|
||||
String pluginFailed(String scriptPath);
|
||||
String cannotDownloadPlugin(String scriptPath);
|
||||
|
||||
String parentUpdateFailed(String message);
|
||||
}
|
||||
|
||||
@@ -15,3 +15,5 @@ branchCreationConflict = Cannot create branch {0} since it conflicts with branch
|
||||
|
||||
pluginFailed = Plugin JavaScript {0} failed to load
|
||||
cannotDownloadPlugin = Cannot download JavaScript plugin from: {0}.
|
||||
|
||||
parentUpdateFailed = Setting parent project failed: {0}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.google.gerrit.client.Dispatcher;
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.GitwebLink;
|
||||
import com.google.gerrit.client.ui.Hyperlink;
|
||||
import com.google.gerrit.client.ui.ParentProjectBox;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.ProjectAccess;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
@@ -55,6 +56,10 @@ public class ProjectAccessEditor extends Composite implements
|
||||
@UiField
|
||||
Hyperlink parentProject;
|
||||
|
||||
@UiField
|
||||
@Editor.Ignore
|
||||
ParentProjectBox parentProjectBox;
|
||||
|
||||
@UiField
|
||||
DivElement history;
|
||||
|
||||
@@ -106,6 +111,11 @@ public class ProjectAccessEditor extends Composite implements
|
||||
parentProject.setText(parent.get());
|
||||
parentProject.setTargetHistoryToken( //
|
||||
Dispatcher.toProjectAdmin(parent, ProjectScreen.ACCESS));
|
||||
|
||||
parentProjectBox.setVisible(editing && value.canChangeParent());
|
||||
parentProjectBox.setProject(value.getProjectName());
|
||||
parentProjectBox.setParentProject(value.getInheritsFrom());
|
||||
parentProject.setVisible(!parentProjectBox.isVisible());
|
||||
} else {
|
||||
inheritsFrom.getStyle().setDisplay(Display.NONE);
|
||||
}
|
||||
@@ -135,6 +145,7 @@ public class ProjectAccessEditor extends Composite implements
|
||||
}
|
||||
}
|
||||
value.setLocal(keep);
|
||||
value.setInheritsFrom(parentProjectBox.getParentProjectName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,6 +56,9 @@ limitations under the License.
|
||||
<div ui:field='inheritsFrom' class='{style.inheritsFrom}'>
|
||||
<span class='{style.parentTitle}'><ui:msg>Rights Inherit From:</ui:msg></span>
|
||||
<q:Hyperlink ui:field='parentProject' styleName='{style.parentLink}'/>
|
||||
<q:ParentProjectBox
|
||||
ui:field='parentProjectBox'
|
||||
visible='false'/>
|
||||
</div>
|
||||
<div ui:field='history' class='{style.history}'>
|
||||
<span class='{style.historyTitle}'><ui:msg>History:</ui:msg></span>
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.gerrit.client.admin;
|
||||
import static com.google.gerrit.common.ProjectAccessUtil.mergeSections;
|
||||
import static com.google.gerrit.common.ProjectAccessUtil.removeEmptyPermissionsAndSections;
|
||||
|
||||
import com.google.gerrit.client.ErrorDialog;
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.config.CapabilityInfo;
|
||||
import com.google.gerrit.client.config.ConfigServerApi;
|
||||
@@ -28,6 +29,7 @@ import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.ProjectAccess;
|
||||
import com.google.gerrit.common.errors.UpdateParentFailedException;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
@@ -45,6 +47,7 @@ import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||
import com.google.gwtjsonrpc.client.RemoteJsonException;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -205,6 +208,7 @@ public class ProjectAccessScreen extends ProjectScreen {
|
||||
access.getRevision(), //
|
||||
message, //
|
||||
access.getLocal(), //
|
||||
access.getInheritsFrom(), //
|
||||
new GerritCallback<ProjectAccess>() {
|
||||
@Override
|
||||
public void onSuccess(ProjectAccess newAccess) {
|
||||
@@ -250,8 +254,16 @@ public class ProjectAccessScreen extends ProjectScreen {
|
||||
public void onFailure(Throwable caught) {
|
||||
error.clear();
|
||||
enable(true);
|
||||
if (caught instanceof RemoteJsonException
|
||||
&& caught.getMessage().startsWith(
|
||||
UpdateParentFailedException.MESSAGE)) {
|
||||
new ErrorDialog(Gerrit.M.parentUpdateFailed(caught.getMessage()
|
||||
.substring(UpdateParentFailedException.MESSAGE.length() + 1)))
|
||||
.center();
|
||||
} else {
|
||||
super.onFailure(caught);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -275,6 +287,7 @@ public class ProjectAccessScreen extends ProjectScreen {
|
||||
access.getRevision(), //
|
||||
message, //
|
||||
access.getLocal(), //
|
||||
access.getInheritsFrom(), //
|
||||
new GerritCallback<Change.Id>() {
|
||||
@Override
|
||||
public void onSuccess(Change.Id changeId) {
|
||||
|
||||
@@ -110,6 +110,15 @@ public class ProjectApi {
|
||||
});
|
||||
}
|
||||
|
||||
public static void getChildren(Project.NameKey name, boolean recursive,
|
||||
AsyncCallback<JsArray<ProjectInfo>> cb) {
|
||||
RestApi view = project(name).view("children");
|
||||
if (recursive) {
|
||||
view.addParameterTrue("recursive");
|
||||
}
|
||||
view.get(cb);
|
||||
}
|
||||
|
||||
public static void getDescription(Project.NameKey name,
|
||||
AsyncCallback<NativeString> cb) {
|
||||
project(name).view("description").get(cb);
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2013 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.client.ui;
|
||||
|
||||
import com.google.gerrit.client.projects.ProjectApi;
|
||||
import com.google.gerrit.client.projects.ProjectInfo;
|
||||
import com.google.gerrit.client.rpc.Natives;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.SuggestBox;
|
||||
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ParentProjectBox extends Composite {
|
||||
private final NpTextBox textBox;
|
||||
private final SuggestBox suggestBox;
|
||||
private final ParentProjectNameSuggestOracle suggestOracle;
|
||||
|
||||
public ParentProjectBox() {
|
||||
textBox = new NpTextBox();
|
||||
suggestOracle = new ParentProjectNameSuggestOracle();
|
||||
suggestBox = new SuggestBox(suggestOracle, textBox);
|
||||
initWidget(suggestBox);
|
||||
}
|
||||
|
||||
public void setVisibleLength(int len) {
|
||||
textBox.setVisibleLength(len);
|
||||
}
|
||||
|
||||
public void setProject(final Project.NameKey project) {
|
||||
suggestOracle.setProject(project);
|
||||
}
|
||||
|
||||
public void setParentProject(final Project.NameKey parent) {
|
||||
suggestBox.setText(parent != null ? parent.get() : "");
|
||||
}
|
||||
|
||||
public Project.NameKey getParentProjectName() {
|
||||
final String projectName = suggestBox.getText().trim();
|
||||
if (projectName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new Project.NameKey(projectName);
|
||||
}
|
||||
|
||||
private static class ParentProjectNameSuggestOracle extends ProjectNameSuggestOracle {
|
||||
private Set<String> exclude = new HashSet<String>();
|
||||
|
||||
public void setProject(Project.NameKey project) {
|
||||
exclude.clear();
|
||||
exclude.add(project.get());
|
||||
ProjectApi.getChildren(project, true, new AsyncCallback<JsArray<ProjectInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(JsArray<ProjectInfo> result) {
|
||||
for (ProjectInfo p : Natives.asList(result)) {
|
||||
exclude.add(p.name());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _onRequestSuggestions(Request req, final Callback callback) {
|
||||
super._onRequestSuggestions(req, new Callback() {
|
||||
public void onSuggestionsReady(Request request, Response response) {
|
||||
if (exclude.size() > 0) {
|
||||
Set<Suggestion> filteredSuggestions =
|
||||
new HashSet<Suggestion>(response.getSuggestions());
|
||||
for (Suggestion s : response.getSuggestions()) {
|
||||
if (exclude.contains(s.getReplacementString())) {
|
||||
filteredSuggestions.remove(s);
|
||||
}
|
||||
}
|
||||
response.setSuggestions(filteredSuggestions);
|
||||
}
|
||||
callback.onSuggestionsReady(request, response);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,15 @@ import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.ProjectAccess;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.SetParent;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
@@ -35,9 +38,11 @@ import java.util.List;
|
||||
|
||||
class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
||||
interface Factory {
|
||||
ChangeProjectAccess create(@Assisted Project.NameKey projectName,
|
||||
ChangeProjectAccess create(
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
|
||||
@Nullable @Assisted String message);
|
||||
}
|
||||
|
||||
@@ -45,17 +50,21 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
ChangeProjectAccess(final ProjectAccessFactory.Factory projectAccessFactory,
|
||||
final ProjectControl.Factory projectControlFactory,
|
||||
final ProjectCache projectCache, final GroupBackend groupBackend,
|
||||
final MetaDataUpdate.User metaDataUpdateFactory,
|
||||
ChangeProjectAccess(ProjectAccessFactory.Factory projectAccessFactory,
|
||||
ProjectControl.Factory projectControlFactory,
|
||||
ProjectCache projectCache, GroupBackend groupBackend,
|
||||
MetaDataUpdate.User metaDataUpdateFactory,
|
||||
AllProjectsNameProvider allProjects,
|
||||
Provider<SetParent> setParent,
|
||||
|
||||
@Assisted final Project.NameKey projectName,
|
||||
@Nullable @Assisted final ObjectId base,
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
|
||||
@Nullable @Assisted String message) {
|
||||
super(projectControlFactory, groupBackend, metaDataUpdateFactory,
|
||||
projectName, base, sectionList, message, true);
|
||||
allProjects, setParent, projectName, base, sectionList,
|
||||
parentProjectName, message, true);
|
||||
this.projectAccessFactory = projectAccessFactory;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,8 @@ class ProjectAccessFactory extends Handler<ProjectAccess> {
|
||||
detail.setOwnerOf(ownerOf);
|
||||
detail.setCanUpload(pc.isOwner()
|
||||
|| (metaConfigControl.isVisible() && metaConfigControl.canUpload()));
|
||||
detail.setCanChangeParent(pc.getCurrentUser().getCapabilities()
|
||||
.canAdministrateServer());
|
||||
detail.setConfigVisible(pc.isOwner() || metaConfigControl.isVisible());
|
||||
detail.setLabelTypes(pc.getLabelTypes());
|
||||
return detail;
|
||||
|
||||
@@ -22,16 +22,23 @@ import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.common.errors.InvalidNameException;
|
||||
import com.google.gerrit.common.errors.NoSuchGroupException;
|
||||
import com.google.gerrit.common.errors.UpdateParentFailedException;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||
import com.google.gerrit.httpd.rpc.Handler;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.account.GroupBackends;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.RefControl;
|
||||
import com.google.gerrit.server.project.SetParent;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
@@ -47,27 +54,32 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
private final ProjectControl.Factory projectControlFactory;
|
||||
protected final GroupBackend groupBackend;
|
||||
private final MetaDataUpdate.User metaDataUpdateFactory;
|
||||
private final AllProjectsNameProvider allProjects;
|
||||
private final Provider<SetParent> setParent;
|
||||
|
||||
protected final Project.NameKey projectName;
|
||||
protected final ObjectId base;
|
||||
private List<AccessSection> sectionList;
|
||||
private final Project.NameKey parentProjectName;
|
||||
protected String message;
|
||||
private boolean checkIfOwner;
|
||||
|
||||
protected ProjectAccessHandler(
|
||||
final ProjectControl.Factory projectControlFactory,
|
||||
final GroupBackend groupBackend,
|
||||
final MetaDataUpdate.User metaDataUpdateFactory,
|
||||
final Project.NameKey projectName, final ObjectId base,
|
||||
final List<AccessSection> sectionList, final String message,
|
||||
final boolean checkIfOwner) {
|
||||
protected ProjectAccessHandler(ProjectControl.Factory projectControlFactory,
|
||||
GroupBackend groupBackend, MetaDataUpdate.User metaDataUpdateFactory,
|
||||
AllProjectsNameProvider allProjects, Provider<SetParent> setParent,
|
||||
Project.NameKey projectName, ObjectId base,
|
||||
List<AccessSection> sectionList, Project.NameKey parentProjectName,
|
||||
String message, boolean checkIfOwner) {
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.groupBackend = groupBackend;
|
||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||
this.allProjects = allProjects;
|
||||
this.setParent = setParent;
|
||||
|
||||
this.projectName = projectName;
|
||||
this.base = base;
|
||||
this.sectionList = sectionList;
|
||||
this.parentProjectName = parentProjectName;
|
||||
this.message = message;
|
||||
this.checkIfOwner = checkIfOwner;
|
||||
}
|
||||
@@ -75,7 +87,7 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
@Override
|
||||
public final T call() throws NoSuchProjectException, IOException,
|
||||
ConfigInvalidException, InvalidNameException, NoSuchGroupException,
|
||||
OrmException {
|
||||
OrmException, UpdateParentFailedException {
|
||||
final ProjectControl projectControl =
|
||||
projectControlFactory.controlFor(projectName);
|
||||
|
||||
@@ -120,6 +132,20 @@ public abstract class ProjectAccessHandler<T> extends Handler<T> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.getProject().getNameKey().equals(allProjects.get()) &&
|
||||
!config.getProject().getParent(allProjects.get()).equals(parentProjectName)) {
|
||||
try {
|
||||
setParent.get().validateParentUpdate(projectControl, parentProjectName.get());
|
||||
} catch (AuthException e) {
|
||||
throw new UpdateParentFailedException(e.getMessage(), e);
|
||||
} catch (ResourceConflictException e) {
|
||||
throw new UpdateParentFailedException(e.getMessage(), e);
|
||||
} catch (UnprocessableEntityException e) {
|
||||
throw new UpdateParentFailedException(e.getMessage(), e);
|
||||
}
|
||||
config.getProject().setParentName(parentProjectName);
|
||||
}
|
||||
|
||||
if (message != null && !message.isEmpty()) {
|
||||
if (!message.endsWith("\n")) {
|
||||
message += "\n";
|
||||
|
||||
@@ -56,14 +56,16 @@ class ProjectAdminServiceImpl implements ProjectAdminService {
|
||||
@Override
|
||||
public void changeProjectAccess(Project.NameKey projectName,
|
||||
String baseRevision, String msg, List<AccessSection> sections,
|
||||
AsyncCallback<ProjectAccess> cb) {
|
||||
changeProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
|
||||
Project.NameKey parentProjectName, AsyncCallback<ProjectAccess> cb) {
|
||||
changeProjectAccessFactory.create(projectName, getBase(baseRevision),
|
||||
sections, parentProjectName, msg).to(cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reviewProjectAccess(Project.NameKey projectName,
|
||||
String baseRevision, String msg, List<AccessSection> sections,
|
||||
AsyncCallback<Change.Id> cb) {
|
||||
reviewProjectAccessFactory.create(projectName, getBase(baseRevision), sections, msg).to(cb);
|
||||
Project.NameKey parentProjectName, AsyncCallback<Change.Id> cb) {
|
||||
reviewProjectAccessFactory.create(projectName, getBase(baseRevision),
|
||||
sections, parentProjectName, msg).to(cb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.change.ChangeResource;
|
||||
import com.google.gerrit.server.change.PostReviewers;
|
||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
@@ -39,6 +40,7 @@ import com.google.gerrit.server.mail.CreateChangeSender;
|
||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
import com.google.gerrit.server.project.SetParent;
|
||||
import com.google.gerrit.server.util.TimeUtil;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
@@ -60,9 +62,11 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
|
||||
LoggerFactory.getLogger(ReviewProjectAccess.class);
|
||||
|
||||
interface Factory {
|
||||
ReviewProjectAccess create(@Assisted Project.NameKey projectName,
|
||||
ReviewProjectAccess create(
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
|
||||
@Nullable @Assisted String message);
|
||||
}
|
||||
|
||||
@@ -84,13 +88,17 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
|
||||
ChangeControl.GenericFactory changeFactory,
|
||||
ChangeIndexer indexer, ChangeHooks hooks,
|
||||
CreateChangeSender.Factory createChangeSenderFactory,
|
||||
AllProjectsNameProvider allProjects,
|
||||
Provider<SetParent> setParent,
|
||||
|
||||
@Assisted Project.NameKey projectName,
|
||||
@Assisted("projectName") Project.NameKey projectName,
|
||||
@Nullable @Assisted ObjectId base,
|
||||
@Assisted List<AccessSection> sectionList,
|
||||
@Nullable @Assisted("parentProjectName") Project.NameKey parentProjectName,
|
||||
@Nullable @Assisted String message) {
|
||||
super(projectControlFactory, groupBackend, metaDataUpdateFactory,
|
||||
projectName, base, sectionList, message, false);
|
||||
allProjects, setParent, projectName, base, sectionList,
|
||||
parentProjectName, message, false);
|
||||
this.db = db;
|
||||
this.user = user;
|
||||
this.patchSetInfoFactory = patchSetInfoFactory;
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class SetParent implements RestModifyView<ProjectResource, Input> {
|
||||
public class SetParent implements RestModifyView<ProjectResource, Input> {
|
||||
static class Input {
|
||||
@DefaultInput
|
||||
String parent;
|
||||
@@ -63,41 +63,14 @@ class SetParent implements RestModifyView<ProjectResource, Input> {
|
||||
BadRequestException, ResourceConflictException,
|
||||
ResourceNotFoundException, UnprocessableEntityException, IOException {
|
||||
ProjectControl ctl = rsrc.getControl();
|
||||
validateParentUpdate(ctl, input.parent);
|
||||
IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
|
||||
if (!user.getCapabilities().canAdministrateServer()) {
|
||||
throw new AuthException("not administrator");
|
||||
}
|
||||
|
||||
if (rsrc.getNameKey().equals(allProjects)) {
|
||||
throw new ResourceConflictException("cannot set parent of "
|
||||
+ allProjects.get());
|
||||
}
|
||||
|
||||
input.parent = Strings.emptyToNull(input.parent);
|
||||
if (input.parent != null) {
|
||||
ProjectState parent = cache.get(new Project.NameKey(input.parent));
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("parent project " + input.parent
|
||||
+ " not found");
|
||||
}
|
||||
|
||||
if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
|
||||
@Override
|
||||
public boolean apply(ProjectState input) {
|
||||
return input.getProject().getNameKey().equals(rsrc.getNameKey());
|
||||
}
|
||||
}).isPresent()) {
|
||||
throw new ResourceConflictException("cycle exists between "
|
||||
+ rsrc.getName() + " and " + parent.getProject().getName());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
MetaDataUpdate md = updateFactory.create(rsrc.getNameKey());
|
||||
try {
|
||||
ProjectConfig config = ProjectConfig.read(md);
|
||||
Project project = config.getProject();
|
||||
project.setParentName(input.parent);
|
||||
project.setParentName(Strings.emptyToNull(input.parent));
|
||||
|
||||
String msg = Strings.emptyToNull(input.commitMessage);
|
||||
if (msg == null) {
|
||||
@@ -124,4 +97,39 @@ class SetParent implements RestModifyView<ProjectResource, Input> {
|
||||
"invalid project.config: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void validateParentUpdate(final ProjectControl ctl, String newParent)
|
||||
throws AuthException, ResourceConflictException,
|
||||
UnprocessableEntityException {
|
||||
IdentifiedUser user = (IdentifiedUser) ctl.getCurrentUser();
|
||||
if (!user.getCapabilities().canAdministrateServer()) {
|
||||
throw new AuthException("not administrator");
|
||||
}
|
||||
|
||||
if (ctl.getProject().getNameKey().equals(allProjects)) {
|
||||
throw new ResourceConflictException("cannot set parent of "
|
||||
+ allProjects.get());
|
||||
}
|
||||
|
||||
newParent = Strings.emptyToNull(newParent);
|
||||
if (newParent != null) {
|
||||
ProjectState parent = cache.get(new Project.NameKey(newParent));
|
||||
if (parent == null) {
|
||||
throw new UnprocessableEntityException("parent project " + newParent
|
||||
+ " not found");
|
||||
}
|
||||
|
||||
if (Iterables.tryFind(parent.tree(), new Predicate<ProjectState>() {
|
||||
@Override
|
||||
public boolean apply(ProjectState input) {
|
||||
return input.getProject().getNameKey()
|
||||
.equals(ctl.getProject().getNameKey());
|
||||
}
|
||||
}).isPresent()) {
|
||||
throw new ResourceConflictException("cycle exists between "
|
||||
+ ctl.getProject().getName() + " and "
|
||||
+ parent.getProject().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user