mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Send Differential e-mails in user's language
Summary: Works this way: - Select users' language with multiplexing. - Select default language otherwise (it can be different from current user's language). - Build body and subject for each user individually. - Set the original language after sending the mails. Test Plan: - Comment on a diff of user with custom translation. - Set default to a custom translation. Comment on a diff of user with default translation. - Set default to a default translation. Comment on a diff of user with default translation. Repeat with/without multiplexing. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T1139 Differential Revision: https://secure.phabricator.com/D2774
This commit is contained in:
parent
112acf11cf
commit
e84f9f9ec9
7 changed files with 165 additions and 57 deletions
|
@ -62,9 +62,7 @@ abstract class PhabricatorController extends AphrontController {
|
|||
|
||||
$translation = $user->getTranslation();
|
||||
if ($translation &&
|
||||
$translation != PhabricatorEnv::getEnvConfig('translation.provider') &&
|
||||
class_exists($translation) &&
|
||||
is_subclass_of($translation, 'PhabricatorTranslation')) {
|
||||
$translation != PhabricatorEnv::getEnvConfig('translation.provider')) {
|
||||
$translation = newv($translation, array());
|
||||
PhutilTranslator::getInstance()
|
||||
->setLanguage($translation->getLanguage())
|
||||
|
|
|
@ -20,6 +20,9 @@ final class DifferentialCommentMail extends DifferentialMail {
|
|||
|
||||
protected $changedByCommit;
|
||||
|
||||
private $addedReviewers;
|
||||
private $addedCCs;
|
||||
|
||||
public function setChangedByCommit($changed_by_commit) {
|
||||
$this->changedByCommit = $changed_by_commit;
|
||||
return $this;
|
||||
|
@ -87,20 +90,11 @@ final class DifferentialCommentMail extends DifferentialMail {
|
|||
return $verb;
|
||||
}
|
||||
|
||||
protected function renderBody() {
|
||||
|
||||
$comment = $this->getComment();
|
||||
|
||||
$actor = $this->getActorName();
|
||||
$name = $this->getRevision()->getTitle();
|
||||
$verb = $this->getVerb();
|
||||
|
||||
$body = array();
|
||||
|
||||
$body[] = "{$actor} has {$verb} the revision \"{$name}\".";
|
||||
protected function prepareBody() {
|
||||
parent::prepareBody();
|
||||
|
||||
// If the commented added reviewers or CCs, list them explicitly.
|
||||
$meta = $comment->getMetadata();
|
||||
$meta = $this->getComment()->getMetadata();
|
||||
$m_reviewers = idx(
|
||||
$meta,
|
||||
DifferentialComment::METADATA_ADDED_REVIEWERS,
|
||||
|
@ -113,16 +107,32 @@ final class DifferentialCommentMail extends DifferentialMail {
|
|||
if ($load) {
|
||||
$handles = id(new PhabricatorObjectHandleData($load))->loadHandles();
|
||||
if ($m_reviewers) {
|
||||
$body[] = 'Added Reviewers: '.$this->renderHandleList(
|
||||
$handles,
|
||||
$m_reviewers);
|
||||
$this->addedReviewers = $this->renderHandleList($handles, $m_reviewers);
|
||||
}
|
||||
if ($m_cc) {
|
||||
$body[] = 'Added CCs: '.$this->renderHandleList(
|
||||
$handles,
|
||||
$m_cc);
|
||||
$this->addedCCs = $this->renderHandleList($handles, $m_cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function renderBody() {
|
||||
|
||||
$comment = $this->getComment();
|
||||
|
||||
$actor = $this->getActorName();
|
||||
$name = $this->getRevision()->getTitle();
|
||||
$verb = $this->getVerb();
|
||||
|
||||
$body = array();
|
||||
|
||||
$body[] = "{$actor} has {$verb} the revision \"{$name}\".";
|
||||
|
||||
if ($this->addedReviewers) {
|
||||
$body[] = 'Added Reviewers: '.$this->addedReviewers;
|
||||
}
|
||||
if ($this->addedCCs) {
|
||||
$body[] = 'Added CCs: '.$this->addedCCs;
|
||||
}
|
||||
|
||||
$body[] = null;
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ abstract class DifferentialMail {
|
|||
}
|
||||
|
||||
$cc_phids = $this->getCCPHIDs();
|
||||
$body = $this->buildBody();
|
||||
$attachments = $this->buildAttachments();
|
||||
|
||||
$template = new PhabricatorMetaMTAMail();
|
||||
|
@ -90,10 +89,6 @@ abstract class DifferentialMail {
|
|||
}
|
||||
|
||||
$template
|
||||
->setSubject($this->renderSubject())
|
||||
->setSubjectPrefix($this->getSubjectPrefix())
|
||||
->setVarySubjectPrefix($this->renderVaryPrefix())
|
||||
->setBody($body)
|
||||
->setIsHTML($this->shouldMarkMailAsHTML())
|
||||
->setParentMessageID($this->parentMessageID)
|
||||
->addHeader('Thread-Topic', $this->getThreadTopic());
|
||||
|
@ -172,25 +167,62 @@ abstract class DifferentialMail {
|
|||
$phids = array_keys($phids);
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$objects = id(new PhabricatorObjectHandleData($phids))->loadObjects();
|
||||
|
||||
$event = new PhabricatorEvent(
|
||||
PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL,
|
||||
array(
|
||||
'mail' => $template,
|
||||
)
|
||||
);
|
||||
PhutilEventEngine::dispatchEvent($event);
|
||||
$to_handles = array_select_keys($handles, $to_phids);
|
||||
$cc_handles = array_select_keys($handles, $cc_phids);
|
||||
|
||||
$template = $event->getValue('mail');
|
||||
$this->prepareBody();
|
||||
|
||||
$mails = $reply_handler->multiplexMail(
|
||||
$template,
|
||||
array_select_keys($handles, $to_phids),
|
||||
array_select_keys($handles, $cc_phids));
|
||||
$mails = $reply_handler->multiplexMail($template, $to_handles, $cc_handles);
|
||||
|
||||
foreach ($mails as $mail) {
|
||||
$mail->saveAndSend();
|
||||
$original_translator = PhutilTranslator::getInstance();
|
||||
if (!PhabricatorMetaMTAMail::shouldMultiplexAllMail()) {
|
||||
$translation = PhabricatorEnv::newObjectFromConfig(
|
||||
'translation.provider');
|
||||
$translator = id(new PhutilTranslator())
|
||||
->setLanguage($translation->getLanguage())
|
||||
->addTranslations($translation->getTranslations());
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($mails as $mail) {
|
||||
if (PhabricatorMetaMTAMail::shouldMultiplexAllMail()) {
|
||||
$translation = newv($mail->getTranslation($objects), array());
|
||||
$translator = id(new PhutilTranslator())
|
||||
->setLanguage($translation->getLanguage())
|
||||
->addTranslations($translation->getTranslations());
|
||||
PhutilTranslator::setInstance($translator);
|
||||
}
|
||||
|
||||
$body =
|
||||
$this->buildBody()."\n".
|
||||
$reply_handler->getRecipientsSummary($to_handles, $cc_handles);
|
||||
|
||||
$mail
|
||||
->setSubject($this->renderSubject())
|
||||
->setSubjectPrefix($this->getSubjectPrefix())
|
||||
->setVarySubjectPrefix($this->renderVaryPrefix())
|
||||
->setBody($body);
|
||||
|
||||
$event = new PhabricatorEvent(
|
||||
PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL,
|
||||
array(
|
||||
'mail' => $mail,
|
||||
)
|
||||
);
|
||||
PhutilEventEngine::dispatchEvent($event);
|
||||
$mail = $event->getValue('mail');
|
||||
|
||||
$mail->saveAndSend();
|
||||
}
|
||||
|
||||
} catch (Exception $ex) {
|
||||
PhutilTranslator::setInstance($original_translator);
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
PhutilTranslator::setInstance($original_translator);
|
||||
}
|
||||
|
||||
protected function getMailTags() {
|
||||
|
@ -205,6 +237,17 @@ abstract class DifferentialMail {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @{method:buildBody} is called once for each e-mail recipient to allow
|
||||
* translating text to his language. This method can be used to load data that
|
||||
* don't need translation and use them later in @{method:buildBody}.
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
protected function prepareBody() {
|
||||
}
|
||||
|
||||
protected function buildBody() {
|
||||
|
||||
$body = $this->renderBody();
|
||||
|
@ -369,6 +412,8 @@ EOTEXT;
|
|||
$body = array();
|
||||
foreach ($aux_fields as $field) {
|
||||
$field->setRevision($this->getRevision());
|
||||
// TODO: Introduce and use getRequiredHandlePHIDsForMail() and load all
|
||||
// handles in prepareBody().
|
||||
$text = $field->renderValueForMail($phase);
|
||||
if ($text !== null) {
|
||||
$body[] = $text;
|
||||
|
|
|
@ -20,6 +20,8 @@ abstract class DifferentialReviewRequestMail extends DifferentialMail {
|
|||
|
||||
protected $comments;
|
||||
|
||||
private $patch;
|
||||
|
||||
public function setComments($comments) {
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
|
@ -40,6 +42,19 @@ abstract class DifferentialReviewRequestMail extends DifferentialMail {
|
|||
$this->setChangesets($changesets);
|
||||
}
|
||||
|
||||
protected function prepareBody() {
|
||||
parent::prepareBody();
|
||||
|
||||
$inline_max_length = PhabricatorEnv::getEnvConfig(
|
||||
'metamta.differential.inline-patches');
|
||||
if ($inline_max_length) {
|
||||
$patch = $this->buildPatch();
|
||||
if (count(explode("\n", $patch)) <= $inline_max_length) {
|
||||
$this->patch = $patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function renderReviewRequestBody() {
|
||||
$revision = $this->getRevision();
|
||||
|
||||
|
@ -65,14 +80,9 @@ abstract class DifferentialReviewRequestMail extends DifferentialMail {
|
|||
$body[] = null;
|
||||
}
|
||||
|
||||
$inline_key = 'metamta.differential.inline-patches';
|
||||
$inline_max_length = PhabricatorEnv::getEnvConfig($inline_key);
|
||||
if ($inline_max_length) {
|
||||
$patch = $this->buildPatch();
|
||||
if (count(explode("\n", $patch)) <= $inline_max_length) {
|
||||
$body[] = 'CHANGE DETAILS';
|
||||
$body[] = $patch;
|
||||
}
|
||||
if ($this->patch) {
|
||||
$body[] = 'CHANGE DETAILS';
|
||||
$body[] = $this->patch;
|
||||
}
|
||||
|
||||
return implode("\n", $body);
|
||||
|
@ -110,14 +120,9 @@ abstract class DifferentialReviewRequestMail extends DifferentialMail {
|
|||
}
|
||||
|
||||
private function buildPatch() {
|
||||
$revision = $this->getRevision();
|
||||
$revision_id = $revision->getID();
|
||||
$diff = new DifferentialDiff();
|
||||
|
||||
$diffs = $revision->loadDiffs();
|
||||
$diff_number = count($diffs);
|
||||
$diff = array_pop($diffs);
|
||||
|
||||
$diff->attachChangesets($diff->loadChangesets());
|
||||
$diff->attachChangesets($this->getChangesets());
|
||||
// TODO: We could batch this to improve performance.
|
||||
foreach ($diff->getChangesets() as $changeset) {
|
||||
$changeset->attachHunks($changeset->loadHunks());
|
||||
|
|
|
@ -71,6 +71,22 @@ abstract class PhabricatorMailReplyHandler {
|
|||
return null;
|
||||
}
|
||||
|
||||
final public function getRecipientsSummary(
|
||||
array $to_handles,
|
||||
array $cc_handles) {
|
||||
assert_instances_of($to_handles, 'PhabricatorObjectHandle');
|
||||
assert_instances_of($cc_handles, 'PhabricatorObjectHandle');
|
||||
|
||||
$body = '';
|
||||
if ($to_handles) {
|
||||
$body .= "To: ".implode(', ', mpull($to_handles, 'getName'))."\n";
|
||||
}
|
||||
if ($cc_handles) {
|
||||
$body .= "Cc: ".implode(', ', mpull($cc_handles, 'getName'))."\n";
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
final public function multiplexMail(
|
||||
PhabricatorMetaMTAMail $mail_template,
|
||||
array $to_handles,
|
||||
|
@ -115,13 +131,12 @@ abstract class PhabricatorMailReplyHandler {
|
|||
$body = $mail_template->getBody();
|
||||
$body .= "\n";
|
||||
if ($to_handles) {
|
||||
$body .= "To: ".implode(', ', mpull($to_handles, 'getName'))."\n";
|
||||
$add_headers['X-Phabricator-To'] = $this->formatPHIDList($to_handles);
|
||||
}
|
||||
if ($cc_handles) {
|
||||
$body .= "Cc: ".implode(', ', mpull($cc_handles, 'getName'))."\n";
|
||||
$add_headers['X-Phabricator-Cc'] = $this->formatPHIDList($cc_handles);
|
||||
}
|
||||
$body .= $this->getRecipientsSummary($to_handles, $cc_handles);
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$mail = clone $mail_template;
|
||||
|
|
|
@ -119,6 +119,28 @@ final class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getTranslation(array $objects) {
|
||||
$default_translation = PhabricatorEnv::getEnvConfig('translation.provider');
|
||||
$return = null;
|
||||
$recipients = array_merge(
|
||||
idx($this->parameters, 'to', array()),
|
||||
idx($this->parameters, 'cc', array()));
|
||||
foreach (array_select_keys($objects, $recipients) as $object) {
|
||||
$translation = null;
|
||||
if ($object instanceof PhabricatorUser) {
|
||||
$translation = $object->getTranslation();
|
||||
}
|
||||
if (!$translation) {
|
||||
$translation = $default_translation;
|
||||
}
|
||||
if ($return && $translation != $return) {
|
||||
return $default_translation;
|
||||
}
|
||||
$return = $translation;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function addHeader($name, $value) {
|
||||
$this->parameters['headers'][$name] = $value;
|
||||
return $this;
|
||||
|
|
|
@ -96,6 +96,19 @@ final class PhabricatorUser extends PhabricatorUserDAO implements PhutilPerson {
|
|||
return $this->sex;
|
||||
}
|
||||
|
||||
public function getTranslation() {
|
||||
try {
|
||||
if ($this->translation &&
|
||||
class_exists($this->translation) &&
|
||||
is_subclass_of($this->translation, 'PhabricatorTranslation')) {
|
||||
return $this->translation;
|
||||
}
|
||||
} catch (PhutilMissingSymbolException $ex) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isLoggedIn() {
|
||||
return !($this->getPHID() === null);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue