Allow admins to index a change even if the branch is not Readable for them

The ChangesCollection rejects the request if the current user doesn't have the
Read permission on the loaded change. Therefore, an attempt to reindex a change:

  PUT /changes/myProject~12345/index

gets rejected even before it reaches the indexing code.

On the other side, the admin can reindex all changes of that project and thus
also index the change 12345:

  POST /projects/myProject/index.changes

Indexing all changes of a project in order to just index one change is too much.
Add a new REST endpoint where a set of change-ids to index is given in the
request body.

  POST /config/server/index.changes
  Content-Type: application/json; charset=UTF-8

  {changes: ["foo~101", "bar~202"]}

Bug: issue 11205
Change-Id: I05fcc5a024c7634a969a7baac9fd61f3d0f3d12a
This commit is contained in:
Saša Živkov
2019-09-05 10:31:41 +02:00
parent 0b175d7109
commit e922306384
6 changed files with 218 additions and 2 deletions

View File

@@ -0,0 +1,83 @@
// Copyright (C) 2019 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.config;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.ChangeFinder;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.restapi.config.IndexChanges.Input;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Set;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@Singleton
public class IndexChanges implements RestModifyView<ConfigResource, Input> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public static class Input {
public Set<String> changes;
}
private final ChangeFinder changeFinder;
private final SchemaFactory<ReviewDb> schemaFactory;
private final ChangeData.Factory changeDataFactory;
private final ChangeIndexer indexer;
@Inject
IndexChanges(
ChangeFinder changeFinder,
SchemaFactory<ReviewDb> schemaFactory,
ChangeData.Factory changeDataFactory,
ChangeIndexer indexer) {
this.changeFinder = changeFinder;
this.schemaFactory = schemaFactory;
this.changeDataFactory = changeDataFactory;
this.indexer = indexer;
}
@Override
public Object apply(ConfigResource resource, Input input) throws OrmException {
if (input == null || input.changes == null) {
return Response.ok("Nothing to index");
}
try (ReviewDb db = schemaFactory.open()) {
for (String id : input.changes) {
for (ChangeNotes n : changeFinder.find(id)) {
try {
indexer.index(changeDataFactory.create(db, n));
logger.atFine().log("Indexed change %s", id);
} catch (IOException e) {
logger.atSevere().withCause(e).log("Failed to index change %s", id);
}
}
}
}
return Response.ok("Indexed changes " + input.changes);
}
}

View File

@@ -37,6 +37,7 @@ public class Module extends RestApiModule {
get(CONFIG_KIND, "version").to(GetVersion.class);
get(CONFIG_KIND, "info").to(GetServerInfo.class);
post(CONFIG_KIND, "check.consistency").to(CheckConsistency.class);
post(CONFIG_KIND, "index.changes").to(IndexChanges.class);
post(CONFIG_KIND, "reload").to(ReloadConfig.class);
get(CONFIG_KIND, "preferences").to(GetPreferences.class);
put(CONFIG_KIND, "preferences").to(SetPreferences.class);