Line data Source code
1 : // Copyright (C) 2017 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 com.google.common.base.Strings; 18 : import com.google.gerrit.entities.HumanComment; 19 : import com.google.gerrit.entities.PatchSet; 20 : import com.google.gerrit.extensions.api.changes.DeleteCommentInput; 21 : import com.google.gerrit.extensions.common.CommentInfo; 22 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 23 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 24 : import com.google.gerrit.extensions.restapi.Response; 25 : import com.google.gerrit.extensions.restapi.RestApiException; 26 : import com.google.gerrit.extensions.restapi.RestModifyView; 27 : import com.google.gerrit.server.CommentsUtil; 28 : import com.google.gerrit.server.CurrentUser; 29 : import com.google.gerrit.server.change.HumanCommentResource; 30 : import com.google.gerrit.server.notedb.ChangeNotes; 31 : import com.google.gerrit.server.permissions.GlobalPermission; 32 : import com.google.gerrit.server.permissions.PermissionBackend; 33 : import com.google.gerrit.server.permissions.PermissionBackendException; 34 : import com.google.gerrit.server.update.BatchUpdate; 35 : import com.google.gerrit.server.update.BatchUpdateOp; 36 : import com.google.gerrit.server.update.ChangeContext; 37 : import com.google.gerrit.server.update.UpdateException; 38 : import com.google.gerrit.server.util.time.TimeUtil; 39 : import com.google.inject.Inject; 40 : import com.google.inject.Provider; 41 : import com.google.inject.Singleton; 42 : import java.io.IOException; 43 : import java.util.List; 44 : import java.util.Optional; 45 : import org.eclipse.jgit.errors.ConfigInvalidException; 46 : 47 : @Singleton 48 : public class DeleteComment implements RestModifyView<HumanCommentResource, DeleteCommentInput> { 49 : 50 : private final Provider<CurrentUser> userProvider; 51 : private final PermissionBackend permissionBackend; 52 : private final BatchUpdate.Factory updateFactory; 53 : private final CommentsUtil commentsUtil; 54 : private final Provider<CommentJson> commentJson; 55 : private final ChangeNotes.Factory notesFactory; 56 : 57 : @Inject 58 : public DeleteComment( 59 : Provider<CurrentUser> userProvider, 60 : PermissionBackend permissionBackend, 61 : BatchUpdate.Factory updateFactory, 62 : CommentsUtil commentsUtil, 63 : Provider<CommentJson> commentJson, 64 138 : ChangeNotes.Factory notesFactory) { 65 138 : this.userProvider = userProvider; 66 138 : this.permissionBackend = permissionBackend; 67 138 : this.updateFactory = updateFactory; 68 138 : this.commentsUtil = commentsUtil; 69 138 : this.commentJson = commentJson; 70 138 : this.notesFactory = notesFactory; 71 138 : } 72 : 73 : @Override 74 : public Response<CommentInfo> apply(HumanCommentResource rsrc, DeleteCommentInput input) 75 : throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException, 76 : UpdateException { 77 3 : CurrentUser user = userProvider.get(); 78 3 : permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER); 79 : 80 3 : if (input == null) { 81 1 : input = new DeleteCommentInput(); 82 : } 83 : 84 3 : String newMessage = getCommentNewMessage(user.asIdentifiedUser().getName(), input.reason); 85 3 : DeleteCommentOp deleteCommentOp = new DeleteCommentOp(rsrc, newMessage); 86 3 : try (BatchUpdate batchUpdate = 87 3 : updateFactory.create(rsrc.getRevisionResource().getProject(), user, TimeUtil.now())) { 88 3 : batchUpdate.addOp(rsrc.getRevisionResource().getChange().getId(), deleteCommentOp).execute(); 89 : } 90 : 91 3 : ChangeNotes updatedNotes = 92 3 : notesFactory.createChecked( 93 3 : rsrc.getRevisionResource().getProject(), 94 3 : rsrc.getRevisionResource().getChangeResource().getId()); 95 3 : List<HumanComment> changeComments = commentsUtil.publishedHumanCommentsByChange(updatedNotes); 96 3 : Optional<HumanComment> updatedComment = 97 3 : changeComments.stream().filter(c -> c.key.equals(rsrc.getComment().key)).findFirst(); 98 3 : if (!updatedComment.isPresent()) { 99 : // This should not happen as this endpoint should not remove the whole comment. 100 0 : throw new ResourceNotFoundException("comment not found: " + rsrc.getComment().key); 101 : } 102 : 103 3 : return Response.ok(commentJson.get().newHumanCommentFormatter().format(updatedComment.get())); 104 : } 105 : 106 : private static String getCommentNewMessage(String name, String reason) { 107 3 : StringBuilder stringBuilder = new StringBuilder("Comment removed by: ").append(name); 108 3 : if (!Strings.isNullOrEmpty(reason)) { 109 1 : stringBuilder.append("; Reason: ").append(reason); 110 : } 111 3 : return stringBuilder.toString(); 112 : } 113 : 114 : private class DeleteCommentOp implements BatchUpdateOp { 115 : private final HumanCommentResource rsrc; 116 : private final String newMessage; 117 : 118 3 : DeleteCommentOp(HumanCommentResource rsrc, String newMessage) { 119 3 : this.rsrc = rsrc; 120 3 : this.newMessage = newMessage; 121 3 : } 122 : 123 : @Override 124 : public boolean updateChange(ChangeContext ctx) 125 : throws ResourceConflictException, ResourceNotFoundException { 126 3 : PatchSet.Id psId = ctx.getChange().currentPatchSetId(); 127 3 : commentsUtil.deleteCommentByRewritingHistory( 128 3 : ctx.getUpdate(psId), rsrc.getComment().key, newMessage); 129 3 : return true; 130 : } 131 : } 132 : }