Line data Source code
1 : // Copyright (C) 2016 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.extensions.api.changes.AssigneeInput; 19 : import com.google.gerrit.extensions.api.changes.NotifyHandling; 20 : import com.google.gerrit.extensions.api.changes.ReviewerInput; 21 : import com.google.gerrit.extensions.client.ReviewerState; 22 : import com.google.gerrit.extensions.common.AccountInfo; 23 : import com.google.gerrit.extensions.restapi.AuthException; 24 : import com.google.gerrit.extensions.restapi.BadRequestException; 25 : import com.google.gerrit.extensions.restapi.Response; 26 : import com.google.gerrit.extensions.restapi.RestApiException; 27 : import com.google.gerrit.extensions.restapi.RestModifyView; 28 : import com.google.gerrit.extensions.webui.UiAction; 29 : import com.google.gerrit.server.IdentifiedUser; 30 : import com.google.gerrit.server.ReviewerSet; 31 : import com.google.gerrit.server.account.AccountLoader; 32 : import com.google.gerrit.server.account.AccountResolver; 33 : import com.google.gerrit.server.approval.ApprovalsUtil; 34 : import com.google.gerrit.server.change.ChangeResource; 35 : import com.google.gerrit.server.change.ReviewerModifier; 36 : import com.google.gerrit.server.change.ReviewerModifier.ReviewerModification; 37 : import com.google.gerrit.server.change.SetAssigneeOp; 38 : import com.google.gerrit.server.permissions.ChangePermission; 39 : import com.google.gerrit.server.permissions.PermissionBackend; 40 : import com.google.gerrit.server.permissions.PermissionBackendException; 41 : import com.google.gerrit.server.update.BatchUpdate; 42 : import com.google.gerrit.server.update.UpdateException; 43 : import com.google.gerrit.server.util.time.TimeUtil; 44 : import com.google.inject.Inject; 45 : import com.google.inject.Singleton; 46 : import java.io.IOException; 47 : import org.eclipse.jgit.errors.ConfigInvalidException; 48 : 49 : @Singleton 50 : public class PutAssignee 51 : implements RestModifyView<ChangeResource, AssigneeInput>, UiAction<ChangeResource> { 52 : 53 : private final BatchUpdate.Factory updateFactory; 54 : private final AccountResolver accountResolver; 55 : private final SetAssigneeOp.Factory assigneeFactory; 56 : private final ReviewerModifier reviewerModifier; 57 : private final AccountLoader.Factory accountLoaderFactory; 58 : private final PermissionBackend permissionBackend; 59 : private final ApprovalsUtil approvalsUtil; 60 : 61 : @Inject 62 : PutAssignee( 63 : BatchUpdate.Factory updateFactory, 64 : AccountResolver accountResolver, 65 : SetAssigneeOp.Factory assigneeFactory, 66 : ReviewerModifier reviewerModifier, 67 : AccountLoader.Factory accountLoaderFactory, 68 : PermissionBackend permissionBackend, 69 145 : ApprovalsUtil approvalsUtil) { 70 145 : this.updateFactory = updateFactory; 71 145 : this.accountResolver = accountResolver; 72 145 : this.assigneeFactory = assigneeFactory; 73 145 : this.reviewerModifier = reviewerModifier; 74 145 : this.accountLoaderFactory = accountLoaderFactory; 75 145 : this.permissionBackend = permissionBackend; 76 145 : this.approvalsUtil = approvalsUtil; 77 145 : } 78 : 79 : @Override 80 : public Response<AccountInfo> apply(ChangeResource rsrc, AssigneeInput input) 81 : throws RestApiException, UpdateException, IOException, PermissionBackendException, 82 : ConfigInvalidException { 83 7 : rsrc.permissions().check(ChangePermission.EDIT_ASSIGNEE); 84 : 85 7 : input.assignee = Strings.nullToEmpty(input.assignee).trim(); 86 7 : if (input.assignee.isEmpty()) { 87 1 : throw new BadRequestException("missing assignee field"); 88 : } 89 : 90 6 : IdentifiedUser assignee = accountResolver.resolve(input.assignee).asUniqueUser(); 91 : try { 92 6 : permissionBackend 93 6 : .absentUser(assignee.getAccountId()) 94 6 : .change(rsrc.getNotes()) 95 6 : .check(ChangePermission.READ); 96 1 : } catch (AuthException e) { 97 1 : throw new AuthException("read not permitted for " + input.assignee, e); 98 6 : } 99 : 100 6 : try (BatchUpdate bu = 101 6 : updateFactory.create(rsrc.getChange().getProject(), rsrc.getUser(), TimeUtil.now())) { 102 6 : SetAssigneeOp op = assigneeFactory.create(assignee); 103 6 : bu.addOp(rsrc.getId(), op); 104 : 105 6 : ReviewerSet currentReviewers = approvalsUtil.getReviewers(rsrc.getNotes()); 106 6 : if (!currentReviewers.all().contains(assignee.getAccountId())) { 107 6 : ReviewerModification reviewersAddition = addAssigneeAsCC(rsrc, input.assignee); 108 6 : reviewersAddition.op.suppressEmail(); 109 6 : bu.addOp(rsrc.getId(), reviewersAddition.op); 110 : } 111 : 112 6 : bu.execute(); 113 6 : return Response.ok(accountLoaderFactory.create(true).fillOne(assignee.getAccountId())); 114 : } 115 : } 116 : 117 : private ReviewerModification addAssigneeAsCC(ChangeResource rsrc, String assignee) 118 : throws IOException, PermissionBackendException, ConfigInvalidException { 119 6 : ReviewerInput reviewerInput = new ReviewerInput(); 120 6 : reviewerInput.reviewer = assignee; 121 6 : reviewerInput.state = ReviewerState.CC; 122 6 : reviewerInput.confirmed = true; 123 6 : reviewerInput.notify = NotifyHandling.NONE; 124 6 : return reviewerModifier.prepare(rsrc.getNotes(), rsrc.getUser(), reviewerInput, false); 125 : } 126 : 127 : @Override 128 : public UiAction.Description getDescription(ChangeResource rsrc) { 129 57 : return new UiAction.Description() 130 57 : .setLabel("Edit Assignee") 131 57 : .setVisible(rsrc.permissions().testCond(ChangePermission.EDIT_ASSIGNEE)); 132 : } 133 : }