Merge "Refactor SetAccess and CreateAccessChange."
diff --git a/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java b/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
index 338ff0d..3e8002b 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateAccessChange.java
@@ -14,17 +14,11 @@
package com.google.gerrit.server.restapi.project;
-import static com.google.gerrit.server.project.ProjectCache.illegalState;
-import static com.google.gerrit.server.update.context.RefUpdateContext.RefUpdateType.CHANGE_MODIFICATION;
-
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.gerrit.entities.AccessSection;
import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.InvalidNameException;
import com.google.gerrit.extensions.api.access.ProjectAccessInput;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -33,89 +27,35 @@
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.Sequences;
-import com.google.gerrit.server.approval.ApprovalsUtil;
-import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeJson;
-import com.google.gerrit.server.git.meta.MetaDataUpdate;
-import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.permissions.ProjectPermission;
-import com.google.gerrit.server.permissions.RefPermission;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectResource;
-import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.UpdateException;
-import com.google.gerrit.server.update.context.RefUpdateContext;
-import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
@Singleton
public class CreateAccessChange implements RestModifyView<ProjectResource, ProjectAccessInput> {
- private final PermissionBackend permissionBackend;
- private final Sequences seq;
- private final ChangeInserter.Factory changeInserterFactory;
- private final BatchUpdate.Factory updateFactory;
- private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
private final SetAccessUtil setAccess;
private final ChangeJson.Factory jsonFactory;
- private final ProjectCache projectCache;
- private final ProjectConfig.Factory projectConfigFactory;
+ private final RepoMetaDataUpdater repoMetaDataUpdater;
@Inject
CreateAccessChange(
- PermissionBackend permissionBackend,
- ChangeInserter.Factory changeInserterFactory,
- BatchUpdate.Factory updateFactory,
- Sequences seq,
- Provider<MetaDataUpdate.User> metaDataUpdateFactory,
SetAccessUtil accessUtil,
ChangeJson.Factory jsonFactory,
- ProjectCache projectCache,
- ProjectConfig.Factory projectConfigFactory) {
- this.permissionBackend = permissionBackend;
- this.seq = seq;
- this.changeInserterFactory = changeInserterFactory;
- this.updateFactory = updateFactory;
- this.metaDataUpdateFactory = metaDataUpdateFactory;
+ RepoMetaDataUpdater repoMetaDataUpdater) {
this.setAccess = accessUtil;
this.jsonFactory = jsonFactory;
- this.projectCache = projectCache;
- this.projectConfigFactory = projectConfigFactory;
+ this.repoMetaDataUpdater = repoMetaDataUpdater;
}
@Override
public Response<ChangeInfo> apply(ProjectResource rsrc, ProjectAccessInput input)
- throws PermissionBackendException, AuthException, IOException, ConfigInvalidException,
- InvalidNameException, UpdateException, RestApiException {
- PermissionBackend.ForProject forProject =
- permissionBackend.user(rsrc.getUser()).project(rsrc.getNameKey());
- if (!check(forProject, ProjectPermission.READ_CONFIG)) {
- throw new AuthException(RefNames.REFS_CONFIG + " not visible");
- }
- if (!check(forProject, ProjectPermission.WRITE_CONFIG)) {
- try {
- forProject.ref(RefNames.REFS_CONFIG).check(RefPermission.CREATE_CHANGE);
- } catch (AuthException denied) {
- throw new AuthException("cannot create change for " + RefNames.REFS_CONFIG, denied);
- }
- }
- projectCache
- .get(rsrc.getNameKey())
- .orElseThrow(illegalState(rsrc.getNameKey()))
- .checkStatePermitsWrite();
-
- MetaDataUpdate.User metaDataUpdateUser = metaDataUpdateFactory.get();
+ throws PermissionBackendException, IOException, ConfigInvalidException, InvalidNameException,
+ UpdateException, RestApiException {
ImmutableList<AccessSection> removals =
setAccess.getAccessSections(input.remove, /* rejectNonResolvableGroups= */ false);
ImmutableList<AccessSection> additions =
@@ -123,81 +63,30 @@
Project.NameKey newParentProjectName =
input.parent == null ? null : Project.nameKey(input.parent);
-
- try (MetaDataUpdate md = metaDataUpdateUser.create(rsrc.getNameKey())) {
- ProjectConfig config = projectConfigFactory.read(md);
- ObjectId oldCommit = config.getRevision();
- String oldCommitSha1 = oldCommit == null ? null : oldCommit.getName();
-
- setAccess.validateChanges(config, removals, additions);
- setAccess.applyChanges(config, removals, additions);
- try {
- setAccess.setParentName(
- rsrc.getUser().asIdentifiedUser(),
- config,
- rsrc.getNameKey(),
- newParentProjectName,
- false);
- } catch (AuthException e) {
- throw new IllegalStateException(e);
- }
-
- if (!Strings.isNullOrEmpty(input.message)) {
- if (!input.message.endsWith("\n")) {
- input.message += "\n";
- }
- md.setMessage(input.message);
- } else {
- md.setMessage("Review access change\n");
- }
-
- md.setInsertChangeId(true);
- Change.Id changeId = Change.id(seq.nextChangeId());
- try (RefUpdateContext ctx = RefUpdateContext.open(CHANGE_MODIFICATION)) {
- RevCommit commit =
- config.commitToNewRef(
- md, PatchSet.id(changeId, Change.INITIAL_PATCH_SET_ID).toRefName());
-
- if (commit.name().equals(oldCommitSha1)) {
- throw new BadRequestException("no change");
- }
-
- try (ObjectInserter objInserter = md.getRepository().newObjectInserter();
- ObjectReader objReader = objInserter.newReader();
- RevWalk rw = new RevWalk(objReader);
- BatchUpdate bu =
- updateFactory.create(rsrc.getNameKey(), rsrc.getUser(), TimeUtil.now())) {
- bu.setRepository(md.getRepository(), rw, objInserter);
- ChangeInserter ins = newInserter(changeId, commit);
- bu.insertChange(ins);
- bu.execute();
- return Response.created(jsonFactory.noOptions().format(ins.getChange()));
- }
- }
+ String message = !Strings.isNullOrEmpty(input.message) ? input.message : "Review access change";
+ try {
+ Change change =
+ repoMetaDataUpdater.updateAndCreateChangeForReview(
+ rsrc.getNameKey(),
+ rsrc.getUser(),
+ message,
+ config -> {
+ setAccess.validateChanges(config, removals, additions);
+ setAccess.applyChanges(config, removals, additions);
+ try {
+ setAccess.setParentName(
+ rsrc.getUser().asIdentifiedUser(),
+ config,
+ rsrc.getNameKey(),
+ newParentProjectName,
+ false);
+ } catch (AuthException e) {
+ throw new IllegalStateException(e);
+ }
+ });
+ return Response.created(jsonFactory.noOptions().format(change));
} catch (InvalidNameException e) {
throw new BadRequestException(e.toString());
}
}
-
- // ProjectConfig doesn't currently support fusing into a BatchUpdate.
- @SuppressWarnings("deprecation")
- private ChangeInserter newInserter(Change.Id changeId, RevCommit commit) {
- return changeInserterFactory
- .create(changeId, commit, RefNames.REFS_CONFIG)
- .setMessage(
- // Same message as in ReceiveCommits.CreateRequest.
- ApprovalsUtil.renderMessageWithApprovals(1, ImmutableMap.of(), ImmutableMap.of()))
- .setValidate(false)
- .setUpdateRef(false);
- }
-
- private boolean check(PermissionBackend.ForProject perm, ProjectPermission p)
- throws PermissionBackendException {
- try {
- perm.check(p);
- return true;
- } catch (AuthException denied) {
- return false;
- }
- }
}
diff --git a/java/com/google/gerrit/server/restapi/project/RepoMetaDataUpdater.java b/java/com/google/gerrit/server/restapi/project/RepoMetaDataUpdater.java
new file mode 100644
index 0000000..c45a009
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/project/RepoMetaDataUpdater.java
@@ -0,0 +1,215 @@
+// Copyright (C) 2024 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.server.restapi.project;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.gerrit.server.project.ProjectCache.illegalState;
+import static com.google.gerrit.server.update.context.RefUpdateContext.RefUpdateType.CHANGE_MODIFICATION;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.exceptions.InvalidNameException;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.CreateGroupPermissionSyncer;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.Sequences;
+import com.google.gerrit.server.approval.ApprovalsUtil;
+import com.google.gerrit.server.change.ChangeInserter;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.MetaDataUpdate.User;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
+import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectConfig;
+import com.google.gerrit.server.update.BatchUpdate;
+import com.google.gerrit.server.update.UpdateException;
+import com.google.gerrit.server.update.context.RefUpdateContext;
+import com.google.gerrit.server.util.time.TimeUtil;
+import java.io.IOException;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+/** Updates repo refs/meta/config content. */
+@Singleton
+public class RepoMetaDataUpdater {
+ private final CreateGroupPermissionSyncer createGroupPermissionSyncer;
+ private final Provider<User> metaDataUpdateFactory;
+ private final ProjectConfig.Factory projectConfigFactory;
+ private final ProjectCache projectCache;
+ private final ChangeInserter.Factory changeInserterFactory;
+ private final Sequences seq;
+
+ private final BatchUpdate.Factory updateFactory;
+
+ private final PermissionBackend permissionBackend;
+
+ @Inject
+ RepoMetaDataUpdater(
+ CreateGroupPermissionSyncer createGroupPermissionSyncer,
+ Provider<User> metaDataUpdateFactory,
+ ProjectConfig.Factory projectConfigFactory,
+ ProjectCache projectCache,
+ ChangeInserter.Factory changeInserterFactory,
+ Sequences seq,
+ BatchUpdate.Factory updateFactory,
+ PermissionBackend permissionBackend) {
+ this.createGroupPermissionSyncer = createGroupPermissionSyncer;
+ this.metaDataUpdateFactory = metaDataUpdateFactory;
+ this.projectConfigFactory = projectConfigFactory;
+ this.projectCache = projectCache;
+ this.changeInserterFactory = changeInserterFactory;
+ this.seq = seq;
+ this.updateFactory = updateFactory;
+ this.permissionBackend = permissionBackend;
+ }
+
+ public Change updateAndCreateChangeForReview(
+ Project.NameKey projectName,
+ CurrentUser user,
+ String message,
+ ProjectConfigUpdater projectConfigUpdater)
+ throws ConfigInvalidException, IOException, RestApiException, UpdateException,
+ InvalidNameException, PermissionBackendException {
+ checkArgument(!message.isBlank(), "The message must not be empty");
+ message = validateMessage(message);
+
+ PermissionBackend.ForProject forProject = permissionBackend.user(user).project(projectName);
+ if (!check(forProject, ProjectPermission.READ_CONFIG)) {
+ throw new AuthException(RefNames.REFS_CONFIG + " not visible");
+ }
+ if (!check(forProject, ProjectPermission.WRITE_CONFIG)) {
+ try {
+ forProject.ref(RefNames.REFS_CONFIG).check(RefPermission.CREATE_CHANGE);
+ } catch (AuthException denied) {
+ throw new AuthException("cannot create change for " + RefNames.REFS_CONFIG, denied);
+ }
+ }
+ projectCache.get(projectName).orElseThrow(illegalState(projectName)).checkStatePermitsWrite();
+
+ try (MetaDataUpdate md = metaDataUpdateFactory.get().create(projectName)) {
+ ProjectConfig config = projectConfigFactory.read(md);
+ ObjectId oldCommit = config.getRevision();
+ String oldCommitSha1 = oldCommit == null ? null : oldCommit.getName();
+
+ projectConfigUpdater.update(config);
+ md.setMessage(message);
+ md.setInsertChangeId(true);
+
+ Change.Id changeId = Change.id(seq.nextChangeId());
+ try (RefUpdateContext ctx = RefUpdateContext.open(CHANGE_MODIFICATION)) {
+ RevCommit commit =
+ config.commitToNewRef(
+ md, PatchSet.id(changeId, Change.INITIAL_PATCH_SET_ID).toRefName());
+
+ if (commit.name().equals(oldCommitSha1)) {
+ throw new BadRequestException("no change");
+ }
+
+ try (ObjectInserter objInserter = md.getRepository().newObjectInserter();
+ ObjectReader objReader = objInserter.newReader();
+ RevWalk rw = new RevWalk(objReader);
+ BatchUpdate bu = updateFactory.create(projectName, user, TimeUtil.now())) {
+ bu.setRepository(md.getRepository(), rw, objInserter);
+ ChangeInserter ins = newInserter(changeId, commit);
+ bu.insertChange(ins);
+ bu.execute();
+ return ins.getChange();
+ }
+ }
+ }
+ }
+
+ public void updateWithoutReview(
+ Project.NameKey projectName, String message, ProjectConfigUpdater projectConfigUpdater)
+ throws ConfigInvalidException, IOException, PermissionBackendException, AuthException,
+ ResourceConflictException, InvalidNameException, BadRequestException {
+ updateWithoutReview(
+ projectName, message, /*skipPermissionsCheck=*/ false, projectConfigUpdater);
+ }
+
+ public void updateWithoutReview(
+ Project.NameKey projectName,
+ String message,
+ boolean skipPermissionsCheck,
+ ProjectConfigUpdater projectConfigUpdater)
+ throws ConfigInvalidException, IOException, PermissionBackendException, AuthException,
+ ResourceConflictException, InvalidNameException, BadRequestException {
+ message = validateMessage(message);
+ if (!skipPermissionsCheck) {
+ permissionBackend.currentUser().project(projectName).check(ProjectPermission.WRITE_CONFIG);
+ }
+
+ try (MetaDataUpdate md = metaDataUpdateFactory.get().create(projectName)) {
+ ProjectConfig config = projectConfigFactory.read(md);
+
+ projectConfigUpdater.update(config);
+ md.setMessage(message);
+ config.commit(md);
+ projectCache.evictAndReindex(config.getProject());
+ createGroupPermissionSyncer.syncIfNeeded();
+ }
+ }
+
+ private String validateMessage(String message) {
+ if (!message.endsWith("\n")) {
+ return message + "\n";
+ }
+ return message;
+ }
+
+ // ProjectConfig doesn't currently support fusing into a BatchUpdate.
+ @SuppressWarnings("deprecation")
+ private ChangeInserter newInserter(Change.Id changeId, RevCommit commit) {
+ return changeInserterFactory
+ .create(changeId, commit, RefNames.REFS_CONFIG)
+ .setMessage(
+ // Same message as in ReceiveCommits.CreateRequest.
+ ApprovalsUtil.renderMessageWithApprovals(1, ImmutableMap.of(), ImmutableMap.of()))
+ .setValidate(false)
+ .setUpdateRef(false);
+ }
+
+ private boolean check(PermissionBackend.ForProject perm, ProjectPermission p)
+ throws PermissionBackendException {
+ try {
+ perm.check(p);
+ return true;
+ } catch (AuthException denied) {
+ return false;
+ }
+ }
+
+ @FunctionalInterface
+ public interface ProjectConfigUpdater {
+ void update(ProjectConfig config)
+ throws BadRequestException, InvalidNameException, PermissionBackendException,
+ ResourceConflictException, AuthException;
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/project/SetAccess.java b/java/com/google/gerrit/server/restapi/project/SetAccess.java
index e4e4373..75fe280 100644
--- a/java/com/google/gerrit/server/restapi/project/SetAccess.java
+++ b/java/com/google/gerrit/server/restapi/project/SetAccess.java
@@ -29,15 +29,11 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.CreateGroupPermissionSyncer;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.RefPermission;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -49,92 +45,72 @@
public class SetAccess implements RestModifyView<ProjectResource, ProjectAccessInput> {
protected final GroupBackend groupBackend;
private final PermissionBackend permissionBackend;
- private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
private final GetAccess getAccess;
- private final ProjectCache projectCache;
private final Provider<IdentifiedUser> identifiedUser;
private final SetAccessUtil accessUtil;
- private final CreateGroupPermissionSyncer createGroupPermissionSyncer;
- private final ProjectConfig.Factory projectConfigFactory;
+ private final RepoMetaDataUpdater repoMetaDataUpdater;
@Inject
private SetAccess(
GroupBackend groupBackend,
PermissionBackend permissionBackend,
- Provider<MetaDataUpdate.User> metaDataUpdateFactory,
- ProjectCache projectCache,
GetAccess getAccess,
Provider<IdentifiedUser> identifiedUser,
SetAccessUtil accessUtil,
- CreateGroupPermissionSyncer createGroupPermissionSyncer,
- ProjectConfig.Factory projectConfigFactory) {
+ RepoMetaDataUpdater repoMetaDataUpdater) {
this.groupBackend = groupBackend;
this.permissionBackend = permissionBackend;
- this.metaDataUpdateFactory = metaDataUpdateFactory;
this.getAccess = getAccess;
- this.projectCache = projectCache;
this.identifiedUser = identifiedUser;
this.accessUtil = accessUtil;
- this.createGroupPermissionSyncer = createGroupPermissionSyncer;
- this.projectConfigFactory = projectConfigFactory;
+ this.repoMetaDataUpdater = repoMetaDataUpdater;
}
@Override
public Response<ProjectAccessInfo> apply(ProjectResource rsrc, ProjectAccessInput input)
throws Exception {
- MetaDataUpdate.User metaDataUpdateUser = metaDataUpdateFactory.get();
-
validateInput(input);
- ProjectConfig config;
-
ImmutableList<AccessSection> removals =
accessUtil.getAccessSections(input.remove, /* rejectNonResolvableGroups= */ false);
ImmutableList<AccessSection> additions =
accessUtil.getAccessSections(input.add, /* rejectNonResolvableGroups= */ true);
- try (MetaDataUpdate md = metaDataUpdateUser.create(rsrc.getNameKey())) {
- config = projectConfigFactory.read(md);
-
- // Check that the user has the right permissions.
- boolean checkedAdmin = false;
- for (AccessSection section : Iterables.concat(additions, removals)) {
- boolean isGlobalCapabilities = AccessSection.GLOBAL_CAPABILITIES.equals(section.getName());
- if (isGlobalCapabilities) {
- if (!checkedAdmin) {
- permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
- checkedAdmin = true;
- }
- } else {
- permissionBackend
- .currentUser()
- .project(rsrc.getNameKey())
- .ref(section.getName())
- .check(RefPermission.WRITE_CONFIG);
- }
- }
-
- accessUtil.validateChanges(config, removals, additions);
- accessUtil.applyChanges(config, removals, additions);
-
- accessUtil.setParentName(
- identifiedUser.get(),
- config,
+ String message = !Strings.isNullOrEmpty(input.message) ? input.message : "Modify access rules";
+ try {
+ this.repoMetaDataUpdater.updateWithoutReview(
rsrc.getNameKey(),
- input.parent == null ? null : Project.nameKey(input.parent),
- !checkedAdmin);
+ message,
+ /*skipPermissionsCheck=*/ true,
+ config -> {
+ // Check that the user has the right permissions.
+ boolean checkedAdmin = false;
+ for (AccessSection section : Iterables.concat(additions, removals)) {
+ boolean isGlobalCapabilities =
+ AccessSection.GLOBAL_CAPABILITIES.equals(section.getName());
+ if (isGlobalCapabilities) {
+ if (!checkedAdmin) {
+ permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
+ checkedAdmin = true;
+ }
+ } else {
+ permissionBackend
+ .currentUser()
+ .project(rsrc.getNameKey())
+ .ref(section.getName())
+ .check(RefPermission.WRITE_CONFIG);
+ }
+ }
- if (!Strings.isNullOrEmpty(input.message)) {
- if (!input.message.endsWith("\n")) {
- input.message += "\n";
- }
- md.setMessage(input.message);
- } else {
- md.setMessage("Modify access rules\n");
- }
+ accessUtil.validateChanges(config, removals, additions);
+ accessUtil.applyChanges(config, removals, additions);
- config.commit(md);
- projectCache.evictAndReindex(config.getProject());
- createGroupPermissionSyncer.syncIfNeeded();
+ accessUtil.setParentName(
+ identifiedUser.get(),
+ config,
+ rsrc.getNameKey(),
+ input.parent == null ? null : Project.nameKey(input.parent),
+ !checkedAdmin);
+ });
} catch (InvalidNameException e) {
throw new BadRequestException(e.toString());
} catch (ConfigInvalidException e) {