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 com.google.common.base.Strings; 18 : import com.google.common.flogger.FluentLogger; 19 : import com.google.gerrit.common.Nullable; 20 : import com.google.gerrit.entities.Change; 21 : import com.google.gerrit.entities.PatchSet; 22 : import com.google.gerrit.extensions.restapi.ResourceConflictException; 23 : import com.google.gerrit.server.ChangeMessagesUtil; 24 : import com.google.gerrit.server.ChangeUtil; 25 : import com.google.gerrit.server.PatchSetUtil; 26 : import com.google.gerrit.server.account.AccountState; 27 : import com.google.gerrit.server.extensions.events.ChangeAbandoned; 28 : import com.google.gerrit.server.mail.send.AbandonedSender; 29 : import com.google.gerrit.server.mail.send.MessageIdGenerator; 30 : import com.google.gerrit.server.mail.send.ReplyToChangeSender; 31 : import com.google.gerrit.server.notedb.ChangeUpdate; 32 : import com.google.gerrit.server.update.BatchUpdateOp; 33 : import com.google.gerrit.server.update.ChangeContext; 34 : import com.google.gerrit.server.update.PostUpdateContext; 35 : import com.google.inject.Inject; 36 : import com.google.inject.assistedinject.Assisted; 37 : 38 : public class AbandonOp implements BatchUpdateOp { 39 20 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 40 : 41 : private final AbandonedSender.Factory abandonedSenderFactory; 42 : private final ChangeMessagesUtil cmUtil; 43 : private final PatchSetUtil psUtil; 44 : private final ChangeAbandoned changeAbandoned; 45 : private final MessageIdGenerator messageIdGenerator; 46 : 47 : private final String msgTxt; 48 : private final AccountState accountState; 49 : 50 : private Change change; 51 : private PatchSet patchSet; 52 : private String mailMessage; 53 : 54 : public interface Factory { 55 : AbandonOp create( 56 : @Assisted @Nullable AccountState accountState, @Assisted @Nullable String msgTxt); 57 : } 58 : 59 : @Inject 60 : AbandonOp( 61 : AbandonedSender.Factory abandonedSenderFactory, 62 : ChangeMessagesUtil cmUtil, 63 : PatchSetUtil psUtil, 64 : ChangeAbandoned changeAbandoned, 65 : MessageIdGenerator messageIdGenerator, 66 : @Assisted @Nullable AccountState accountState, 67 20 : @Assisted @Nullable String msgTxt) { 68 20 : this.abandonedSenderFactory = abandonedSenderFactory; 69 20 : this.cmUtil = cmUtil; 70 20 : this.psUtil = psUtil; 71 20 : this.changeAbandoned = changeAbandoned; 72 20 : this.messageIdGenerator = messageIdGenerator; 73 : 74 20 : this.accountState = accountState; 75 20 : this.msgTxt = Strings.nullToEmpty(msgTxt); 76 20 : } 77 : 78 : @Nullable 79 : public Change getChange() { 80 20 : return change; 81 : } 82 : 83 : @Override 84 : public boolean updateChange(ChangeContext ctx) throws ResourceConflictException { 85 20 : change = ctx.getChange(); 86 20 : PatchSet.Id psId = change.currentPatchSetId(); 87 20 : ChangeUpdate update = ctx.getUpdate(psId); 88 20 : if (!change.isNew()) { 89 1 : throw new ResourceConflictException("change is " + ChangeUtil.status(change)); 90 : } 91 20 : patchSet = psUtil.get(ctx.getNotes(), psId); 92 20 : change.setStatus(Change.Status.ABANDONED); 93 20 : change.setLastUpdatedOn(ctx.getWhen()); 94 : 95 20 : update.setStatus(change.getStatus()); 96 20 : mailMessage = cmUtil.setChangeMessage(ctx, commentMessage(), ChangeMessagesUtil.TAG_ABANDON); 97 20 : return true; 98 : } 99 : 100 : private String commentMessage() { 101 20 : StringBuilder msg = new StringBuilder(); 102 20 : msg.append("Abandoned"); 103 20 : if (!Strings.nullToEmpty(msgTxt).trim().isEmpty()) { 104 2 : msg.append("\n\n"); 105 2 : msg.append(msgTxt.trim()); 106 : } 107 20 : return msg.toString(); 108 : } 109 : 110 : @Override 111 : public void postUpdate(PostUpdateContext ctx) { 112 20 : NotifyResolver.Result notify = ctx.getNotify(change.getId()); 113 : try { 114 20 : ReplyToChangeSender emailSender = 115 20 : abandonedSenderFactory.create(ctx.getProject(), change.getId()); 116 20 : if (accountState != null) { 117 20 : emailSender.setFrom(accountState.account().id()); 118 : } 119 20 : emailSender.setChangeMessage(mailMessage, ctx.getWhen()); 120 20 : emailSender.setNotify(notify); 121 20 : emailSender.setMessageId( 122 20 : messageIdGenerator.fromChangeUpdate(ctx.getRepoView(), patchSet.id())); 123 20 : emailSender.send(); 124 0 : } catch (Exception e) { 125 0 : logger.atSevere().withCause(e).log("Cannot email update for change %s", change.getId()); 126 20 : } 127 20 : changeAbandoned.fire( 128 20 : ctx.getChangeData(change), 129 : patchSet, 130 : accountState, 131 : msgTxt, 132 20 : ctx.getWhen(), 133 20 : notify.handling()); 134 20 : } 135 : }