| // Copyright (C) 2016 The Android Open Source Project | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.gerrit.server.mail.send; | |
| import com.google.common.base.Splitter; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.gerrit.common.Nullable; | |
| import com.google.gerrit.entities.Change; | |
| import com.google.gerrit.entities.NotifyConfig.NotifyType; | |
| import com.google.gerrit.entities.PatchSet; | |
| import com.google.gerrit.entities.PatchSetInfo; | |
| import com.google.gerrit.exceptions.EmailException; | |
| import com.google.gerrit.extensions.api.changes.RecipientType; | |
| import com.google.gerrit.server.patch.filediff.FileDiffOutput; | |
| import com.google.gerrit.server.project.ProjectState; | |
| import com.google.gerrit.server.query.change.ChangeData; | |
| import java.time.Instant; | |
| import java.util.Map; | |
| /** Populates an email for change related notifications. */ | |
| public interface ChangeEmail extends OutgoingEmail.EmailDecorator { | |
| /** Implementations of params interface populate details specific to the notification type. */ | |
| interface ChangeEmailDecorator { | |
| /** | |
| * Stores the reference to the {@link OutgoingEmail} and {@link ChangeEmail} for the subsequent | |
| * calls. | |
| * | |
| * <p>Both init and populateEmailContent can be called multiply times in case of retries. Init | |
| * is therefore responsible for clearing up any changes which are not idempotent and | |
| * initializing data for use in populateEmailContent. | |
| * | |
| * <p>Can be used to adjust any of the behaviour of the {@link | |
| * ChangeEmail#populateEmailContent}. | |
| */ | |
| void init(OutgoingEmail email, ChangeEmail changeEmail) throws EmailException; | |
| /** | |
| * Populate headers, recipients and body of the email. | |
| * | |
| * <p>Method operates on the email provided in the init method. | |
| * | |
| * <p>By default, all the contents and parameters of the email should be set in this method. | |
| */ | |
| void populateEmailContent() throws EmailException; | |
| /** If returns false email is not sent to any recipients. */ | |
| default boolean shouldSendMessage() { | |
| return true; | |
| } | |
| } | |
| /** Mark the email as non-first in the thread to ensure correct headers will be set */ | |
| void markAsReply(); | |
| /** Get change for which the email is being sent. */ | |
| Change getChange(); | |
| /** Get ChangeData for the change corresponding to the email. */ | |
| ChangeData getChangeData(); | |
| /** | |
| * Get Timestamp of the event causing the email. | |
| * | |
| * <p>Provided by {@link #setChangeMessage(String, Instant)}. | |
| */ | |
| @Nullable | |
| Instant getTimestamp(); | |
| /** Specify PatchSet with which the notification is associated with. */ | |
| void setPatchSet(PatchSet ps); | |
| /** Get PatchSet if provided. */ | |
| @Nullable | |
| PatchSet getPatchSet(); | |
| /** Specify PatchSet along with additional data. */ | |
| void setPatchSet(PatchSet ps, PatchSetInfo psi); | |
| /** Specify the summary of what happened to the change. */ | |
| void setChangeMessage(String cm, Instant t); | |
| /** | |
| * Specify if the email should only be sent to attention set. | |
| * | |
| * <p>Only affects users who have corresponding option enabled in the settings. | |
| */ | |
| void setEmailOnlyAttentionSetIfEnabled(boolean value); | |
| /** Get the text of the "cover letter" (processed changeMessage). */ | |
| String getCoverLetter(); | |
| /** Get the patch list corresponding to patch set patchSetId of this change. */ | |
| Map<String, FileDiffOutput> listModifiedFiles(int patchSetId); | |
| /** Get the patch list corresponding to this patch set. */ | |
| Map<String, FileDiffOutput> listModifiedFiles(); | |
| /** Get the number of added lines in a change. */ | |
| int getInsertionsCount(); | |
| /** Get the number of deleted lines in a change. */ | |
| int getDeletionsCount(); | |
| /** Get the project entity the change is in; null if its been deleted. */ | |
| ProjectState getProjectState(); | |
| /** TO or CC all vested parties (change owner, patch set uploader, author). */ | |
| void addAuthors(RecipientType rt); | |
| /** BCC any user who has starred this change. */ | |
| void bccStarredBy(); | |
| /** Include users and groups that want notification of events. */ | |
| void includeWatchers(NotifyType type); | |
| /** Include users and groups that want notification of events. */ | |
| void includeWatchers(NotifyType type, boolean includeWatchersFromNotifyConfig); | |
| /** Any user who has published comments on this change. */ | |
| void ccAllApprovals(); | |
| /** Users who were added as reviewers to this change. */ | |
| void ccExistingReviewers(); | |
| /** Show patch set as unified difference. */ | |
| String getUnifiedDiff(); | |
| /** | |
| * Generate a list of maps representing each line of the unified diff. The line maps will have a | |
| * 'type' key which maps to one of 'common', 'add' or 'remove' and a 'text' key which maps to the | |
| * line's content. | |
| * | |
| * @param sourceDiff the unified diff that we're converting to the map. | |
| * @return map of 'type' to a line's content. | |
| */ | |
| static ImmutableList<ImmutableMap<String, String>> getDiffTemplateData(String sourceDiff) { | |
| ImmutableList.Builder<ImmutableMap<String, String>> result = ImmutableList.builder(); | |
| Splitter lineSplitter = Splitter.on(System.getProperty("line.separator")); | |
| for (String diffLine : lineSplitter.split(sourceDiff)) { | |
| ImmutableMap.Builder<String, String> lineData = ImmutableMap.builder(); | |
| lineData.put("text", diffLine); | |
| // Skip empty lines and lines that look like diff headers. | |
| if (diffLine.isEmpty() || diffLine.startsWith("---") || diffLine.startsWith("+++")) { | |
| lineData.put("type", "common"); | |
| } else { | |
| switch (diffLine.charAt(0)) { | |
| case '+': | |
| lineData.put("type", "add"); | |
| break; | |
| case '-': | |
| lineData.put("type", "remove"); | |
| break; | |
| default: | |
| lineData.put("type", "common"); | |
| break; | |
| } | |
| } | |
| result.add(lineData.build()); | |
| } | |
| return result.build(); | |
| } | |
| } |