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.change; 16 : 17 : import static java.util.Objects.requireNonNull; 18 : 19 : import com.google.common.flogger.FluentLogger; 20 : import com.google.gerrit.entities.Change; 21 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 22 : import com.google.gerrit.extensions.restapi.RestApiException; 23 : import com.google.gerrit.server.ChangeMessagesUtil; 24 : import com.google.gerrit.server.IdentifiedUser; 25 : import com.google.gerrit.server.extensions.events.AssigneeChanged; 26 : import com.google.gerrit.server.mail.send.MessageIdGenerator; 27 : import com.google.gerrit.server.mail.send.SetAssigneeSender; 28 : import com.google.gerrit.server.notedb.ChangeUpdate; 29 : import com.google.gerrit.server.plugincontext.PluginSetContext; 30 : import com.google.gerrit.server.update.BatchUpdateOp; 31 : import com.google.gerrit.server.update.ChangeContext; 32 : import com.google.gerrit.server.update.PostUpdateContext; 33 : import com.google.gerrit.server.util.AccountTemplateUtil; 34 : import com.google.gerrit.server.validators.AssigneeValidationListener; 35 : import com.google.gerrit.server.validators.ValidationException; 36 : import com.google.inject.Inject; 37 : import com.google.inject.Provider; 38 : import com.google.inject.assistedinject.Assisted; 39 : 40 : public class SetAssigneeOp implements BatchUpdateOp { 41 6 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 42 : 43 : public interface Factory { 44 : SetAssigneeOp create(IdentifiedUser assignee); 45 : } 46 : 47 : private final ChangeMessagesUtil cmUtil; 48 : private final PluginSetContext<AssigneeValidationListener> validationListeners; 49 : private final IdentifiedUser newAssignee; 50 : private final AssigneeChanged assigneeChanged; 51 : private final SetAssigneeSender.Factory setAssigneeSenderFactory; 52 : private final Provider<IdentifiedUser> user; 53 : private final IdentifiedUser.GenericFactory userFactory; 54 : private final MessageIdGenerator messageIdGenerator; 55 : 56 : private Change change; 57 : private IdentifiedUser oldAssignee; 58 : 59 : @Inject 60 : SetAssigneeOp( 61 : ChangeMessagesUtil cmUtil, 62 : PluginSetContext<AssigneeValidationListener> validationListeners, 63 : AssigneeChanged assigneeChanged, 64 : SetAssigneeSender.Factory setAssigneeSenderFactory, 65 : Provider<IdentifiedUser> user, 66 : IdentifiedUser.GenericFactory userFactory, 67 : MessageIdGenerator messageIdGenerator, 68 6 : @Assisted IdentifiedUser newAssignee) { 69 6 : this.cmUtil = cmUtil; 70 6 : this.validationListeners = validationListeners; 71 6 : this.assigneeChanged = assigneeChanged; 72 6 : this.setAssigneeSenderFactory = setAssigneeSenderFactory; 73 6 : this.user = user; 74 6 : this.userFactory = userFactory; 75 6 : this.messageIdGenerator = messageIdGenerator; 76 6 : this.newAssignee = requireNonNull(newAssignee, "assignee"); 77 6 : } 78 : 79 : @Override 80 : public boolean updateChange(ChangeContext ctx) throws RestApiException { 81 6 : change = ctx.getChange(); 82 6 : if (newAssignee.getAccountId().equals(change.getAssignee())) { 83 1 : return false; 84 : } 85 : try { 86 6 : validationListeners.runEach( 87 0 : l -> l.validateAssignee(change, newAssignee.getAccount()), ValidationException.class); 88 0 : } catch (ValidationException e) { 89 0 : throw new ResourceConflictException(e.getMessage(), e); 90 6 : } 91 : 92 6 : if (change.getAssignee() != null) { 93 2 : oldAssignee = userFactory.create(change.getAssignee()); 94 : } 95 : 96 6 : ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId()); 97 : // notedb 98 6 : update.setAssignee(newAssignee.getAccountId()); 99 : // reviewdb 100 6 : change.setAssignee(newAssignee.getAccountId()); 101 6 : addMessage(ctx); 102 6 : return true; 103 : } 104 : 105 : private void addMessage(ChangeContext ctx) { 106 6 : StringBuilder msg = new StringBuilder(); 107 6 : msg.append("Assignee "); 108 6 : if (oldAssignee == null) { 109 6 : msg.append("added: "); 110 6 : msg.append(AccountTemplateUtil.getAccountTemplate(newAssignee.getAccountId())); 111 : } else { 112 2 : msg.append("changed from: "); 113 2 : msg.append(AccountTemplateUtil.getAccountTemplate(oldAssignee.getAccountId())); 114 2 : msg.append(" to: "); 115 2 : msg.append(AccountTemplateUtil.getAccountTemplate(newAssignee.getAccountId())); 116 : } 117 6 : cmUtil.setChangeMessage(ctx, msg.toString(), ChangeMessagesUtil.TAG_SET_ASSIGNEE); 118 6 : } 119 : 120 : @Override 121 : public void postUpdate(PostUpdateContext ctx) { 122 : try { 123 6 : SetAssigneeSender emailSender = 124 6 : setAssigneeSenderFactory.create( 125 6 : change.getProject(), change.getId(), newAssignee.getAccountId()); 126 6 : emailSender.setFrom(user.get().getAccountId()); 127 6 : emailSender.setMessageId( 128 6 : messageIdGenerator.fromChangeUpdate(ctx.getRepoView(), change.currentPatchSetId())); 129 6 : emailSender.send(); 130 0 : } catch (Exception err) { 131 0 : logger.atSevere().withCause(err).log( 132 0 : "Cannot send email to new assignee of change %s", change.getId()); 133 6 : } 134 6 : assigneeChanged.fire( 135 6 : ctx.getChangeData(change), 136 6 : ctx.getAccount(), 137 6 : oldAssignee != null ? oldAssignee.state() : null, 138 6 : ctx.getWhen()); 139 6 : } 140 : }