Line data Source code
1 : // Copyright (C) 2009 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.mail.send; 16 : 17 : import static com.google.common.base.Preconditions.checkNotNull; 18 : 19 : import com.google.common.collect.HashBasedTable; 20 : import com.google.common.collect.Table; 21 : import com.google.common.flogger.FluentLogger; 22 : import com.google.gerrit.entities.Account; 23 : import com.google.gerrit.entities.Change; 24 : import com.google.gerrit.entities.LabelType; 25 : import com.google.gerrit.entities.LabelTypes; 26 : import com.google.gerrit.entities.LabelValue; 27 : import com.google.gerrit.entities.NotifyConfig.NotifyType; 28 : import com.google.gerrit.entities.PatchSetApproval; 29 : import com.google.gerrit.entities.Project; 30 : import com.google.gerrit.exceptions.EmailException; 31 : import com.google.gerrit.exceptions.StorageException; 32 : import com.google.gerrit.extensions.api.changes.NotifyHandling; 33 : import com.google.gerrit.server.change.NotifyResolver; 34 : import com.google.inject.Inject; 35 : import com.google.inject.assistedinject.Assisted; 36 : import java.util.Optional; 37 : 38 : /** Send notice about a change successfully merged. */ 39 : public class MergedSender extends ReplyToChangeSender { 40 55 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 41 : 42 : public interface Factory { 43 : MergedSender create( 44 : Project.NameKey project, Change.Id changeId, Optional<String> stickyApprovalDiff); 45 : } 46 : 47 : private final LabelTypes labelTypes; 48 : private final Optional<String> stickyApprovalDiff; 49 : 50 : @Inject 51 : public MergedSender( 52 : EmailArguments args, 53 : @Assisted Project.NameKey project, 54 : @Assisted Change.Id changeId, 55 : @Assisted Optional<String> stickyApprovalDiff) { 56 55 : super(args, "merged", newChangeData(args, project, changeId)); 57 55 : labelTypes = changeData.getLabelTypes(); 58 55 : this.stickyApprovalDiff = stickyApprovalDiff; 59 55 : } 60 : 61 : @Override 62 : public void setNotify(NotifyResolver.Result notify) { 63 53 : checkNotNull(notify); 64 53 : if (!stickyApprovalDiff.isEmpty()) { 65 5 : if (notify.handling() != NotifyHandling.ALL) { 66 1 : logger.atFine().log( 67 : "Requested to notify %s, but for change submission with sticky approval diff," 68 : + " Notify=ALL is enforced.", 69 1 : notify.handling().name()); 70 : } 71 5 : this.notify = NotifyResolver.Result.create(NotifyHandling.ALL, notify.accounts()); 72 : } else { 73 53 : this.notify = notify; 74 : } 75 53 : } 76 : 77 : @Override 78 : protected void init() throws EmailException { 79 : // We want to send the submit email even if the "send only when in attention set" is enabled. 80 55 : emailOnlyAttentionSetIfEnabled = false; 81 : 82 55 : super.init(); 83 : 84 55 : ccAllApprovals(); 85 55 : bccStarredBy(); 86 55 : includeWatchers(NotifyType.ALL_COMMENTS); 87 55 : includeWatchers(NotifyType.SUBMITTED_CHANGES); 88 55 : } 89 : 90 : @Override 91 : protected void formatChange() throws EmailException { 92 55 : appendText(textTemplate("Merged")); 93 : 94 55 : if (useHtml()) { 95 55 : appendHtml(soyHtmlTemplate("MergedHtml")); 96 : } 97 55 : } 98 : 99 : public String getApprovals() { 100 : try { 101 55 : Table<Account.Id, String, PatchSetApproval> pos = HashBasedTable.create(); 102 55 : Table<Account.Id, String, PatchSetApproval> neg = HashBasedTable.create(); 103 55 : for (PatchSetApproval ca : args.approvalsUtil.byPatchSet(changeData.notes(), patchSet.id())) { 104 55 : Optional<LabelType> lt = labelTypes.byLabel(ca.labelId()); 105 55 : if (!lt.isPresent()) { 106 55 : continue; 107 : } 108 46 : if (ca.value() > 0) { 109 46 : pos.put(ca.accountId(), lt.get().getName(), ca); 110 2 : } else if (ca.value() < 0) { 111 0 : neg.put(ca.accountId(), lt.get().getName(), ca); 112 : } 113 46 : } 114 : 115 55 : return format("Approvals", pos) + format("Objections", neg); 116 0 : } catch (StorageException err) { 117 : // Don't list the approvals 118 : } 119 0 : return ""; 120 : } 121 : 122 : private String format(String type, Table<Account.Id, String, PatchSetApproval> approvals) { 123 55 : StringBuilder txt = new StringBuilder(); 124 55 : if (approvals.isEmpty()) { 125 55 : return ""; 126 : } 127 46 : txt.append(type).append(":\n"); 128 46 : for (Account.Id id : approvals.rowKeySet()) { 129 46 : txt.append(" "); 130 46 : txt.append(getNameFor(id)); 131 46 : txt.append(": "); 132 46 : boolean first = true; 133 46 : for (LabelType lt : labelTypes.getLabelTypes()) { 134 46 : PatchSetApproval ca = approvals.get(id, lt.getName()); 135 46 : if (ca == null) { 136 5 : continue; 137 : } 138 : 139 46 : if (first) { 140 46 : first = false; 141 : } else { 142 4 : txt.append("; "); 143 : } 144 : 145 46 : LabelValue v = lt.getValue(ca); 146 46 : if (v != null) { 147 46 : txt.append(v.getText()); 148 : } else { 149 0 : txt.append(lt.getName()); 150 0 : txt.append('='); 151 0 : txt.append(LabelValue.formatValue(ca.value())); 152 : } 153 46 : } 154 46 : txt.append('\n'); 155 46 : } 156 46 : txt.append('\n'); 157 46 : return txt.toString(); 158 : } 159 : 160 : @Override 161 : protected void setupSoyContext() { 162 55 : super.setupSoyContext(); 163 55 : soyContextEmailData.put("approvals", getApprovals()); 164 55 : if (stickyApprovalDiff.isPresent()) { 165 5 : soyContextEmailData.put("stickyApprovalDiff", stickyApprovalDiff.get()); 166 5 : soyContextEmailData.put( 167 5 : "stickyApprovalDiffHtml", getDiffTemplateData(stickyApprovalDiff.get())); 168 : } 169 55 : } 170 : }