public function send()
 {
     $to_phids = $this->getToPHIDs();
     if (!$to_phids) {
         throw new Exception('No "To:" users provided!');
     }
     $cc_phids = $this->getCCPHIDs();
     $subject = $this->buildSubject();
     $body = $this->buildBody();
     $template = new PhabricatorMetaMTAMail();
     $actor_handle = $this->getActorHandle();
     $reply_handler = $this->getReplyHandler();
     if ($actor_handle) {
         $template->setFrom($actor_handle->getPHID());
     }
     $template->setSubject($subject)->setBody($body)->setIsHTML($this->shouldMarkMailAsHTML())->setParentMessageID($this->parentMessageID)->addHeader('Thread-Topic', $this->getRevision()->getTitle());
     $template->setThreadID($this->getThreadID(), $this->isFirstMailAboutRevision());
     if ($this->heraldRulesHeader) {
         $template->addHeader('X-Herald-Rules', $this->heraldRulesHeader);
     }
     $template->setRelatedPHID($this->getRevision()->getPHID());
     $phids = array();
     foreach ($to_phids as $phid) {
         $phids[$phid] = true;
     }
     foreach ($cc_phids as $phid) {
         $phids[$phid] = true;
     }
     $phids = array_keys($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $mails = $reply_handler->multiplexMail($template, array_select_keys($handles, $to_phids), array_select_keys($handles, $cc_phids));
     foreach ($mails as $mail) {
         $mail->saveAndSend();
     }
 }
 private function sendErrorEmail($error, PhabricatorMetaMTAReceivedMail $mail)
 {
     $template = new PhabricatorMetaMTAMail();
     $template->setSubject('Exception: unable to process your mail request');
     $template->setBody($this->buildErrorMailBody($error, $mail));
     $template->setRelatedPHID($mail->getRelatedPHID());
     $phid = $this->getActor()->getPHID();
     $tos = array($phid => PhabricatorObjectHandleData::loadOneHandle($phid));
     $mails = $this->multiplexMail($template, $tos, array());
     foreach ($mails as $email) {
         $email->saveAndSend();
     }
     return true;
 }
    public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
    {
        if ($repository->getDetail('herald-disabled')) {
            return;
        }
        $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
        $rules = HeraldRule::loadAllByContentTypeWithFullData(HeraldContentTypeConfig::CONTENT_TYPE_COMMIT);
        $adapter = new HeraldCommitAdapter($repository, $commit, $data);
        $engine = new HeraldEngine();
        $effects = $engine->applyRules($rules, $adapter);
        $engine->applyEffects($effects, $adapter);
        $email_phids = $adapter->getEmailPHIDs();
        if (!$email_phids) {
            return;
        }
        $xscript = $engine->getTranscript();
        $commit_name = $adapter->getHeraldName();
        $revision = $adapter->loadDifferentialRevision();
        $name = null;
        if ($revision) {
            $name = ' ' . $revision->getTitle();
        }
        $author_phid = $data->getCommitDetail('authorPHID');
        $reviewer_phid = $data->getCommitDetail('reviewerPHID');
        $phids = array_filter(array($author_phid, $reviewer_phid));
        $handles = array();
        if ($phids) {
            $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
        }
        if ($author_phid) {
            $author_name = $handles[$author_phid]->getName();
        } else {
            $author_name = $data->getAuthorName();
        }
        if ($reviewer_phid) {
            $reviewer_name = $handles[$reviewer_phid]->getName();
        } else {
            $reviewer_name = null;
        }
        $who = implode(', ', array_filter(array($author_name, $reviewer_name)));
        $description = $data->getCommitMessage();
        $details = PhabricatorEnv::getProductionURI('/' . $commit_name);
        $differential = $revision ? PhabricatorEnv::getProductionURI('/D' . $revision->getID()) : 'No revision.';
        $files = $adapter->loadAffectedPaths();
        sort($files);
        $files = implode("\n  ", $files);
        $xscript_id = $xscript->getID();
        $manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
        $why_uri = PhabricatorEnv::getProductionURI('/herald/transcript/' . $xscript_id . '/');
        $body = <<<EOBODY
DESCRIPTION
{$description}

DETAILS
  {$details}

DIFFERENTIAL REVISION
  {$differential}

AFFECTED FILES
  {$files}

MANAGE HERALD COMMIT RULES
  {$manage_uri}

WHY DID I GET THIS EMAIL?
  {$why_uri}

EOBODY;
        $subject = "[Herald/Commit] {$commit_name} ({$who}){$name}";
        $mailer = new PhabricatorMetaMTAMail();
        $mailer->setRelatedPHID($commit->getPHID());
        $mailer->addTos($email_phids);
        $mailer->setSubject($subject);
        $mailer->setBody($body);
        $mailer->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
        if ($author_phid) {
            $mailer->setFrom($author_phid);
        }
        $mailer->saveAndSend();
    }
Esempio n. 4
0
 public function send()
 {
     $to_phids = $this->getToPHIDs();
     if (!$to_phids) {
         throw new Exception('No "To:" users provided!');
     }
     $cc_phids = $this->getCCPHIDs();
     $subject = $this->buildSubject();
     $vary_subject = $this->buildVarySubject();
     $body = $this->buildBody();
     $attachments = $this->buildAttachments();
     $template = new PhabricatorMetaMTAMail();
     $actor_handle = $this->getActorHandle();
     $reply_handler = $this->getReplyHandler();
     if ($actor_handle) {
         $template->setFrom($actor_handle->getPHID());
     }
     $template->setSubject($subject)->setVarySubject($vary_subject)->setBody($body)->setIsHTML($this->shouldMarkMailAsHTML())->setParentMessageID($this->parentMessageID)->addHeader('Thread-Topic', $this->getRevision()->getTitle());
     $template->setAttachments($attachments);
     $template->setThreadID($this->getThreadID(), $this->isFirstMailAboutRevision());
     if ($this->heraldRulesHeader) {
         $template->addHeader('X-Herald-Rules', $this->heraldRulesHeader);
     }
     $revision = $this->revision;
     if ($revision) {
         if ($revision->getAuthorPHID()) {
             $template->addHeader('X-Differential-Author', '<' . $revision->getAuthorPHID() . '>');
         }
         if ($revision->getReviewers()) {
             $template->addHeader('X-Differential-Reviewers', '<' . implode('>, <', $revision->getReviewers()) . '>');
         }
         if ($revision->getCCPHIDs()) {
             $template->addHeader('X-Differential-CCs', '<' . implode('>, <', $revision->getCCPHIDs()) . '>');
             // Determine explicit CCs (those added by humans) and put them in a
             // header so users can differentiate between Herald CCs and human CCs.
             $relation_subscribed = DifferentialRevision::RELATION_SUBSCRIBED;
             $raw = $revision->getRawRelations($relation_subscribed);
             $reason_phids = ipull($raw, 'reasonPHID');
             $reason_handles = id(new PhabricatorObjectHandleData($reason_phids))->loadHandles();
             $explicit_cc = array();
             foreach ($raw as $relation) {
                 if (!$relation['reasonPHID']) {
                     continue;
                 }
                 $type = $reason_handles[$relation['reasonPHID']]->getType();
                 if ($type == PhabricatorPHIDConstants::PHID_TYPE_USER) {
                     $explicit_cc[] = $relation['objectPHID'];
                 }
             }
             if ($explicit_cc) {
                 $template->addHeader('X-Differential-Explicit-CCs', '<' . implode('>, <', $explicit_cc) . '>');
             }
         }
     }
     $template->setIsBulk(true);
     $template->setRelatedPHID($this->getRevision()->getPHID());
     $mailtags = $this->getMailTags();
     if ($mailtags) {
         $template->setMailTags($mailtags);
     }
     $phids = array();
     foreach ($to_phids as $phid) {
         $phids[$phid] = true;
     }
     foreach ($cc_phids as $phid) {
         $phids[$phid] = true;
     }
     $phids = array_keys($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $event = new PhabricatorEvent(PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL, array('mail' => $template));
     PhutilEventEngine::dispatchEvent($event);
     $template = $event->getValue('mail');
     $mails = $reply_handler->multiplexMail($template, array_select_keys($handles, $to_phids), array_select_keys($handles, $cc_phids));
     foreach ($mails as $mail) {
         $mail->saveAndSend();
     }
 }
Esempio n. 5
0
 public function send()
 {
     $to_phids = $this->getToPHIDs();
     if (!$to_phids) {
         throw new Exception('No "To:" users provided!');
     }
     $cc_phids = $this->getCCPHIDs();
     $attachments = $this->buildAttachments();
     $template = new PhabricatorMetaMTAMail();
     $actor_handle = $this->getActorHandle();
     $reply_handler = $this->getReplyHandler();
     if ($actor_handle) {
         $template->setFrom($actor_handle->getPHID());
     }
     $template->setIsHTML($this->shouldMarkMailAsHTML())->setParentMessageID($this->parentMessageID)->addHeader('Thread-Topic', $this->getThreadTopic());
     $template->setAttachments($attachments);
     $template->setThreadID($this->getThreadID(), $this->isFirstMailAboutRevision());
     if ($this->heraldRulesHeader) {
         $template->addHeader('X-Herald-Rules', $this->heraldRulesHeader);
     }
     $revision = $this->revision;
     if ($revision) {
         if ($revision->getAuthorPHID()) {
             $template->addHeader('X-Differential-Author', '<' . $revision->getAuthorPHID() . '>');
         }
         $reviewer_phids = $revision->getReviewers();
         if ($reviewer_phids) {
             // Add several headers to support e-mail clients which are not able to
             // create rules using regular expressions or wildcards (namely Outlook).
             $template->addPHIDHeaders('X-Differential-Reviewer', $reviewer_phids);
             // Add it also as a list to allow matching of the first reviewer and
             // also for backwards compatibility.
             $template->addHeader('X-Differential-Reviewers', '<' . implode('>, <', $reviewer_phids) . '>');
         }
         if ($cc_phids) {
             $template->addPHIDHeaders('X-Differential-CC', $cc_phids);
             $template->addHeader('X-Differential-CCs', '<' . implode('>, <', $cc_phids) . '>');
             // Determine explicit CCs (those added by humans) and put them in a
             // header so users can differentiate between Herald CCs and human CCs.
             $relation_subscribed = DifferentialRevision::RELATION_SUBSCRIBED;
             $raw = $revision->getRawRelations($relation_subscribed);
             $reason_phids = ipull($raw, 'reasonPHID');
             $reason_handles = id(new PhabricatorObjectHandleData($reason_phids))->loadHandles();
             $explicit_cc = array();
             foreach ($raw as $relation) {
                 if (!$relation['reasonPHID']) {
                     continue;
                 }
                 $type = $reason_handles[$relation['reasonPHID']]->getType();
                 if ($type == PhabricatorPHIDConstants::PHID_TYPE_USER) {
                     $explicit_cc[] = $relation['objectPHID'];
                 }
             }
             if ($explicit_cc) {
                 $template->addPHIDHeaders('X-Differential-Explicit-CC', $explicit_cc);
                 $template->addHeader('X-Differential-Explicit-CCs', '<' . implode('>, <', $explicit_cc) . '>');
             }
         }
     }
     $template->setIsBulk(true);
     $template->setRelatedPHID($this->getRevision()->getPHID());
     $mailtags = $this->getMailTags();
     if ($mailtags) {
         $template->setMailTags($mailtags);
     }
     $phids = array();
     foreach ($to_phids as $phid) {
         $phids[$phid] = true;
     }
     foreach ($cc_phids as $phid) {
         $phids[$phid] = true;
     }
     $phids = array_keys($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $objects = id(new PhabricatorObjectHandleData($phids))->loadObjects();
     $to_handles = array_select_keys($handles, $to_phids);
     $cc_handles = array_select_keys($handles, $cc_phids);
     $this->prepareBody();
     $mails = $reply_handler->multiplexMail($template, $to_handles, $cc_handles);
     $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);
 }
    public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
    {
        $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
        if (!$data) {
            // TODO: Permanent failure.
            return;
        }
        $rules = HeraldRule::loadAllByContentTypeWithFullData(HeraldContentTypeConfig::CONTENT_TYPE_COMMIT, $commit->getPHID());
        $adapter = new HeraldCommitAdapter($repository, $commit, $data);
        $engine = new HeraldEngine();
        $effects = $engine->applyRules($rules, $adapter);
        $engine->applyEffects($effects, $adapter, $rules);
        $audit_phids = $adapter->getAuditMap();
        if ($audit_phids) {
            $this->createAudits($commit, $audit_phids, $rules);
        }
        $this->createAuditsFromCommitMessage($commit, $data);
        $email_phids = $adapter->getEmailPHIDs();
        if (!$email_phids) {
            return;
        }
        if ($repository->getDetail('herald-disabled')) {
            // This just means "disable email"; audits are (mostly) idempotent.
            return;
        }
        $xscript = $engine->getTranscript();
        $revision = $adapter->loadDifferentialRevision();
        if ($revision) {
            $name = $revision->getTitle();
        } else {
            $name = $data->getSummary();
        }
        $author_phid = $data->getCommitDetail('authorPHID');
        $reviewer_phid = $data->getCommitDetail('reviewerPHID');
        $phids = array_filter(array($author_phid, $reviewer_phid, $commit->getPHID()));
        $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
        $commit_handle = $handles[$commit->getPHID()];
        $commit_name = $commit_handle->getName();
        if ($author_phid) {
            $author_name = $handles[$author_phid]->getName();
        } else {
            $author_name = $data->getAuthorName();
        }
        if ($reviewer_phid) {
            $reviewer_name = $handles[$reviewer_phid]->getName();
        } else {
            $reviewer_name = null;
        }
        $who = implode(', ', array_filter(array($author_name, $reviewer_name)));
        $description = $data->getCommitMessage();
        $commit_uri = PhabricatorEnv::getProductionURI($commit_handle->getURI());
        $differential = $revision ? PhabricatorEnv::getProductionURI('/D' . $revision->getID()) : 'No revision.';
        $files = $adapter->loadAffectedPaths();
        sort($files);
        $files = implode("\n  ", $files);
        $xscript_id = $xscript->getID();
        $manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
        $why_uri = PhabricatorEnv::getProductionURI('/herald/transcript/' . $xscript_id . '/');
        $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit($commit);
        $reply_instructions = $reply_handler->getReplyHandlerInstructions();
        if ($reply_instructions) {
            $reply_instructions = "\n" . "REPLY HANDLER ACTIONS\n" . "  " . $reply_instructions . "\n";
        }
        $body = <<<EOBODY
DESCRIPTION
{$description}

DETAILS
  {$commit_uri}

DIFFERENTIAL REVISION
  {$differential}

AFFECTED FILES
  {$files}
{$reply_instructions}
MANAGE HERALD COMMIT RULES
  {$manage_uri}

WHY DID I GET THIS EMAIL?
  {$why_uri}

EOBODY;
        $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix');
        $subject = trim("{$prefix} {$commit_name}: {$name}");
        $vary_subject = trim("{$prefix} [Commit] {$commit_name}: {$name}");
        $threading = PhabricatorAuditCommentEditor::getMailThreading($commit->getPHID());
        list($thread_id, $thread_topic) = $threading;
        $template = new PhabricatorMetaMTAMail();
        $template->setRelatedPHID($commit->getPHID());
        $template->setSubject($subject);
        $template->setVarySubject($subject);
        $template->setBody($body);
        $template->setThreadID($thread_id, $is_new = true);
        $template->addHeader('Thread-Topic', $thread_topic);
        $template->setIsBulk(true);
        $template->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
        if ($author_phid) {
            $template->setFrom($author_phid);
        }
        $mails = $reply_handler->multiplexMail($template, id(new PhabricatorObjectHandleData($email_phids))->loadHandles(), array());
        foreach ($mails as $mail) {
            $mail->saveAndSend();
        }
    }