blob: 9ee3cbba8bc55731b8339e3dea69ba8fa3268bbf [file] [log] [blame]
// 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.googlesource.gerrit.plugins.deleteproject.database;
import static java.util.Collections.singleton;
import static java.util.stream.Collectors.toList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.UserInitiated;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.ProjectWatches.ProjectWatchKey;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeNotes.Factory.ChangeNotesResult;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.account.InternalAccountQuery;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
public class DatabaseDeleteHandler {
private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final StarredChangesUtil starredChangesUtil;
private final ChangeIndexer indexer;
private final Provider<InternalAccountQuery> accountQueryProvider;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final ChangeNotes.Factory schemaFactoryNoteDb;
private final GitRepositoryManager repoManager;
@Inject
public DatabaseDeleteHandler(
StarredChangesUtil starredChangesUtil,
ChangeIndexer indexer,
ChangeNotes.Factory schemaFactoryNoteDb,
GitRepositoryManager repoManager,
Provider<InternalAccountQuery> accountQueryProvider,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider) {
this.starredChangesUtil = starredChangesUtil;
this.indexer = indexer;
this.accountQueryProvider = accountQueryProvider;
this.accountsUpdateProvider = accountsUpdateProvider;
this.schemaFactoryNoteDb = schemaFactoryNoteDb;
this.repoManager = repoManager;
}
public void delete(Project project) throws IOException {
atomicDelete(project, getChangesListFromNoteDb(project));
}
private List<Change.Id> getChangesListFromNoteDb(Project project) throws IOException {
Project.NameKey projectKey = project.getNameKey();
List<Change.Id> changeIds =
schemaFactoryNoteDb
.scan(repoManager.openRepository(projectKey), projectKey)
.map(ChangeNotesResult::id)
.collect(toList());
log.atFine().log(
"Number of changes in noteDb related to project %s are %d",
projectKey.get(), changeIds.size());
return changeIds;
}
private void deleteChanges(List<Change.Id> changeIds) {
for (Change.Id id : changeIds) {
try {
starredChangesUtil.unstarAllForChangeDeletion(id);
} catch (NoSuchChangeException | IOException e) {
// we can ignore the exception during delete
}
// Delete from the secondary index
indexer.delete(id);
}
}
public void atomicDelete(Project project, List<Change.Id> changeIds) {
deleteChanges(changeIds);
for (AccountState a : accountQueryProvider.get().byWatchedProject(project.getNameKey())) {
Account.Id accountId = a.account().id();
for (ProjectWatchKey watchKey : a.projectWatches().keySet()) {
if (project.getNameKey().equals(watchKey.project())) {
try {
accountsUpdateProvider
.get()
.update(
"Delete Project Watches via API",
accountId,
u -> u.deleteProjectWatches(singleton(watchKey)));
} catch (IOException | ConfigInvalidException e) {
log.atSevere().withCause(e).log(
"Removing watch entry for user %s in project %s failed.",
a.userName().orElse("[unknown]"), project.getName());
}
}
}
}
}
}