Line data Source code
1 : // Copyright (C) 2012 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.restapi.change; 16 : 17 : import static com.google.gerrit.extensions.conditions.BooleanCondition.and; 18 : import static com.google.gerrit.server.permissions.ChangePermission.REVERT; 19 : import static com.google.gerrit.server.permissions.RefPermission.CREATE_CHANGE; 20 : import static com.google.gerrit.server.project.ProjectCache.illegalState; 21 : 22 : import com.google.gerrit.entities.Change; 23 : import com.google.gerrit.entities.PatchSet; 24 : import com.google.gerrit.extensions.api.changes.RevertInput; 25 : import com.google.gerrit.extensions.common.ChangeInfo; 26 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 27 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 28 : import com.google.gerrit.extensions.restapi.Response; 29 : import com.google.gerrit.extensions.restapi.RestApiException; 30 : import com.google.gerrit.extensions.restapi.RestModifyView; 31 : import com.google.gerrit.extensions.webui.UiAction; 32 : import com.google.gerrit.server.ChangeUtil; 33 : import com.google.gerrit.server.PatchSetUtil; 34 : import com.google.gerrit.server.change.ChangeJson; 35 : import com.google.gerrit.server.change.ChangeResource; 36 : import com.google.gerrit.server.git.CommitUtil; 37 : import com.google.gerrit.server.notedb.ChangeNotes; 38 : import com.google.gerrit.server.permissions.PermissionBackend; 39 : import com.google.gerrit.server.permissions.PermissionBackendException; 40 : import com.google.gerrit.server.project.ContributorAgreementsChecker; 41 : import com.google.gerrit.server.project.NoSuchChangeException; 42 : import com.google.gerrit.server.project.NoSuchProjectException; 43 : import com.google.gerrit.server.project.ProjectCache; 44 : import com.google.gerrit.server.project.ProjectState; 45 : import com.google.gerrit.server.update.UpdateException; 46 : import com.google.gerrit.server.util.time.TimeUtil; 47 : import com.google.inject.Inject; 48 : import com.google.inject.Singleton; 49 : import java.io.IOException; 50 : import org.eclipse.jgit.errors.ConfigInvalidException; 51 : 52 : @Singleton 53 : public class Revert 54 : implements RestModifyView<ChangeResource, RevertInput>, UiAction<ChangeResource> { 55 : private final PermissionBackend permissionBackend; 56 : private final PatchSetUtil psUtil; 57 : private final ChangeJson.Factory json; 58 : private final ContributorAgreementsChecker contributorAgreements; 59 : private final ProjectCache projectCache; 60 : private final CommitUtil commitUtil; 61 : 62 : @Inject 63 : Revert( 64 : PermissionBackend permissionBackend, 65 : PatchSetUtil psUtil, 66 : ChangeJson.Factory json, 67 : ContributorAgreementsChecker contributorAgreements, 68 : ProjectCache projectCache, 69 145 : CommitUtil commitUtil) { 70 145 : this.permissionBackend = permissionBackend; 71 145 : this.psUtil = psUtil; 72 145 : this.json = json; 73 145 : this.contributorAgreements = contributorAgreements; 74 145 : this.projectCache = projectCache; 75 145 : this.commitUtil = commitUtil; 76 145 : } 77 : 78 : @Override 79 : public Response<ChangeInfo> apply(ChangeResource rsrc, RevertInput input) 80 : throws IOException, RestApiException, UpdateException, NoSuchChangeException, 81 : PermissionBackendException, NoSuchProjectException, ConfigInvalidException { 82 15 : Change change = rsrc.getChange(); 83 15 : if (!change.isMerged()) { 84 2 : throw new ResourceConflictException("change is " + ChangeUtil.status(change)); 85 : } 86 : 87 14 : contributorAgreements.check(rsrc.getProject(), rsrc.getUser()); 88 14 : permissionBackend.user(rsrc.getUser()).ref(change.getDest()).check(CREATE_CHANGE); 89 14 : projectCache 90 14 : .get(rsrc.getProject()) 91 14 : .orElseThrow(illegalState(rsrc.getProject())) 92 14 : .checkStatePermitsWrite(); 93 14 : rsrc.permissions().check(REVERT); 94 14 : ChangeNotes notes = rsrc.getNotes(); 95 14 : Change.Id changeIdToRevert = notes.getChangeId(); 96 14 : PatchSet.Id patchSetId = notes.getChange().currentPatchSetId(); 97 14 : PatchSet patch = psUtil.get(notes, patchSetId); 98 14 : if (patch == null) { 99 0 : throw new ResourceNotFoundException(changeIdToRevert.toString()); 100 : } 101 14 : return Response.ok( 102 14 : json.noOptions() 103 14 : .format( 104 14 : rsrc.getProject(), 105 14 : commitUtil.createRevertChange(notes, rsrc.getUser(), input, TimeUtil.now()))); 106 : } 107 : 108 : @Override 109 : public UiAction.Description getDescription(ChangeResource rsrc) { 110 57 : Change change = rsrc.getChange(); 111 57 : boolean projectStatePermitsWrite = 112 57 : projectCache.get(rsrc.getProject()).map(ProjectState::statePermitsWrite).orElse(false); 113 57 : return new UiAction.Description() 114 57 : .setLabel("Revert") 115 57 : .setTitle("Revert the change") 116 57 : .setVisible( 117 57 : and( 118 57 : and( 119 57 : change.isMerged() && projectStatePermitsWrite, 120 : permissionBackend 121 57 : .user(rsrc.getUser()) 122 57 : .ref(change.getDest()) 123 57 : .testCond(CREATE_CHANGE)), 124 57 : permissionBackend.user(rsrc.getUser()).change(rsrc.getNotes()).testCond(REVERT))); 125 : } 126 : }