diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java | 141 |
1 files changed, 87 insertions, 54 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java index 0cafe6d0cb..c9d016d953 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Abandon.java @@ -14,6 +14,8 @@ package com.google.gerrit.server.change; +import static com.google.gerrit.extensions.conditions.BooleanCondition.and; + import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; import com.google.gerrit.common.TimeUtil; @@ -21,10 +23,8 @@ import com.google.gerrit.extensions.api.changes.AbandonInput; import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.api.changes.RecipientType; import com.google.gerrit.extensions.common.ChangeInfo; -import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestApiException; -import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.webui.UiAction; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Change; @@ -32,25 +32,27 @@ import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.git.AbandonOp; -import com.google.gerrit.server.project.ChangeControl; +import com.google.gerrit.server.notedb.ChangeNotes; +import com.google.gerrit.server.permissions.ChangePermission; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.update.BatchUpdate; +import com.google.gerrit.server.update.RetryHelper; +import com.google.gerrit.server.update.RetryingRestModifyView; import com.google.gerrit.server.update.UpdateException; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; +import java.io.IOException; import java.util.Collection; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.jgit.errors.ConfigInvalidException; @Singleton -public class Abandon - implements RestModifyView<ChangeResource, AbandonInput>, UiAction<ChangeResource> { - private static final Logger log = LoggerFactory.getLogger(Abandon.class); - +public class Abandon extends RetryingRestModifyView<ChangeResource, AbandonInput, ChangeInfo> + implements UiAction<ChangeResource> { private final Provider<ReviewDb> dbProvider; private final ChangeJson.Factory json; - private final BatchUpdate.Factory batchUpdateFactory; private final AbandonOp.Factory abandonOpFactory; private final NotifyUtil notifyUtil; @@ -58,54 +60,75 @@ public class Abandon Abandon( Provider<ReviewDb> dbProvider, ChangeJson.Factory json, - BatchUpdate.Factory batchUpdateFactory, + RetryHelper retryHelper, AbandonOp.Factory abandonOpFactory, NotifyUtil notifyUtil) { + super(retryHelper); this.dbProvider = dbProvider; this.json = json; - this.batchUpdateFactory = batchUpdateFactory; this.abandonOpFactory = abandonOpFactory; this.notifyUtil = notifyUtil; } @Override - public ChangeInfo apply(ChangeResource req, AbandonInput input) - throws RestApiException, UpdateException, OrmException { - ChangeControl control = req.getControl(); - if (!control.canAbandon(dbProvider.get())) { - throw new AuthException("abandon not permitted"); - } + protected ChangeInfo applyImpl( + BatchUpdate.Factory updateFactory, ChangeResource req, AbandonInput input) + throws RestApiException, UpdateException, OrmException, PermissionBackendException, + IOException, ConfigInvalidException { + req.permissions().database(dbProvider).check(ChangePermission.ABANDON); + + NotifyHandling notify = input.notify == null ? defaultNotify(req.getChange()) : input.notify; Change change = abandon( - control, input.message, input.notify, notifyUtil.resolveAccounts(input.notifyDetails)); + updateFactory, + req.getNotes(), + req.getUser(), + input.message, + notify, + notifyUtil.resolveAccounts(input.notifyDetails)); return json.noOptions().format(change); } - public Change abandon(ChangeControl control) throws RestApiException, UpdateException { - return abandon(control, "", NotifyHandling.ALL, ImmutableListMultimap.of()); + private NotifyHandling defaultNotify(Change change) { + return change.hasReviewStarted() ? NotifyHandling.ALL : NotifyHandling.OWNER; } - public Change abandon(ChangeControl control, String msgTxt) + public Change abandon(BatchUpdate.Factory updateFactory, ChangeNotes notes, CurrentUser user) + throws RestApiException, UpdateException { + return abandon( + updateFactory, + notes, + user, + "", + defaultNotify(notes.getChange()), + ImmutableListMultimap.of()); + } + + public Change abandon( + BatchUpdate.Factory updateFactory, ChangeNotes notes, CurrentUser user, String msgTxt) throws RestApiException, UpdateException { - return abandon(control, msgTxt, NotifyHandling.ALL, ImmutableListMultimap.of()); + return abandon( + updateFactory, + notes, + user, + msgTxt, + defaultNotify(notes.getChange()), + ImmutableListMultimap.of()); } public Change abandon( - ChangeControl control, + BatchUpdate.Factory updateFactory, + ChangeNotes notes, + CurrentUser user, String msgTxt, NotifyHandling notifyHandling, ListMultimap<RecipientType, Account.Id> accountsToNotify) throws RestApiException, UpdateException { - CurrentUser user = control.getUser(); Account account = user.isIdentifiedUser() ? user.asIdentifiedUser().getAccount() : null; AbandonOp op = abandonOpFactory.create(account, msgTxt, notifyHandling, accountsToNotify); try (BatchUpdate u = - batchUpdateFactory.create( - dbProvider.get(), - control.getProject().getNameKey(), - control.getUser(), - TimeUtil.nowTs())) { - u.addOp(control.getId(), op).execute(); + updateFactory.create(dbProvider.get(), notes.getProjectName(), user, TimeUtil.nowTs())) { + u.addOp(notes.getChangeId(), op).execute(); } return op.getChange(); } @@ -115,31 +138,31 @@ public class Abandon * should use the batch instead of abandoning one by one. * * <p>It's the caller's responsibility to ensure that all jobs inside the same batch have the - * matching project from its ChangeControl. Violations will result in a ResourceConflictException. + * matching project from its ChangeData. Violations will result in a ResourceConflictException. */ public void batchAbandon( + BatchUpdate.Factory updateFactory, Project.NameKey project, CurrentUser user, - Collection<ChangeControl> controls, + Collection<ChangeData> changes, String msgTxt, NotifyHandling notifyHandling, ListMultimap<RecipientType, Account.Id> accountsToNotify) throws RestApiException, UpdateException { - if (controls.isEmpty()) { + if (changes.isEmpty()) { return; } Account account = user.isIdentifiedUser() ? user.asIdentifiedUser().getAccount() : null; - try (BatchUpdate u = - batchUpdateFactory.create(dbProvider.get(), project, user, TimeUtil.nowTs())) { - for (ChangeControl control : controls) { - if (!project.equals(control.getProject().getNameKey())) { + try (BatchUpdate u = updateFactory.create(dbProvider.get(), project, user, TimeUtil.nowTs())) { + for (ChangeData change : changes) { + if (!project.equals(change.project())) { throw new ResourceConflictException( String.format( "Project name \"%s\" doesn't match \"%s\"", - control.getProject().getNameKey().get(), project.get())); + change.project().get(), project.get())); } u.addOp( - control.getId(), + change.getId(), abandonOpFactory.create(account, msgTxt, notifyHandling, accountsToNotify)); } u.execute(); @@ -147,31 +170,41 @@ public class Abandon } public void batchAbandon( - Project.NameKey project, CurrentUser user, Collection<ChangeControl> controls, String msgTxt) + BatchUpdate.Factory updateFactory, + Project.NameKey project, + CurrentUser user, + Collection<ChangeData> changes, + String msgTxt) throws RestApiException, UpdateException { - batchAbandon(project, user, controls, msgTxt, NotifyHandling.ALL, ImmutableListMultimap.of()); + batchAbandon( + updateFactory, + project, + user, + changes, + msgTxt, + NotifyHandling.ALL, + ImmutableListMultimap.of()); } public void batchAbandon( - Project.NameKey project, CurrentUser user, Collection<ChangeControl> controls) + BatchUpdate.Factory updateFactory, + Project.NameKey project, + CurrentUser user, + Collection<ChangeData> changes) throws RestApiException, UpdateException { - batchAbandon(project, user, controls, "", NotifyHandling.ALL, ImmutableListMultimap.of()); + batchAbandon( + updateFactory, project, user, changes, "", NotifyHandling.ALL, ImmutableListMultimap.of()); } @Override - public UiAction.Description getDescription(ChangeResource resource) { - boolean canAbandon = false; - try { - canAbandon = resource.getControl().canAbandon(dbProvider.get()); - } catch (OrmException e) { - log.error("Cannot check canAbandon status. Assuming false.", e); - } + public UiAction.Description getDescription(ChangeResource rsrc) { + Change change = rsrc.getChange(); return new UiAction.Description() .setLabel("Abandon") .setTitle("Abandon the change") .setVisible( - resource.getChange().getStatus().isOpen() - && resource.getChange().getStatus() != Change.Status.DRAFT - && canAbandon); + and( + change.getStatus().isOpen(), + rsrc.permissions().database(dbProvider).testCond(ChangePermission.ABANDON))); } } |