protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $title = $mail->getSubject(); if (!$title) { $title = pht('Email Paste'); } $file = PhabricatorPasteEditor::initializeFileForPaste($sender, $title, $mail->getCleanTextBody()); $xactions = array(); $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT)->setNewValue($file->getPHID()); $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE)->setNewValue($title); $xactions[] = id(new PhabricatorPasteTransaction())->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE)->setNewValue(''); // auto-detect $paste = PhabricatorPaste::initializeNewPaste($sender); $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID())); $editor = id(new PhabricatorPasteEditor())->setActor($sender)->setContentSource($content_source)->setContinueOnNoEffect(true); $xactions = $editor->applyTransactions($paste, $xactions); $mail->setRelatedPHID($paste->getPHID()); $subject_prefix = PhabricatorEnv::getEnvConfig('metamta.paste.subject-prefix'); $subject = pht('You successfully created a paste.'); $paste_uri = PhabricatorEnv::getProductionURI($paste->getURI()); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($subject); $body->addTextSection(pht('PASTE LINK'), $paste_uri); id(new PhabricatorMetaMTAMail())->addTos(array($sender->getPHID()))->setSubject($subject)->setSubjectPrefix($subject_prefix)->setFrom($sender->getPHID())->setRelatedPHID($paste->getPHID())->setBody($body->render())->saveAndSend(); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { // Put all the merged commits info int the mail body if this is a merge $merges_caption = ''; // TODO: Make this limit configurable after T6030 $limit = 50; $commit = $this->getObject(); try { $merges = DiffusionPathChange::newFromConduit(id(new ConduitCall('diffusion.mergedcommitsquery', array('commit' => $commit->getCommitIdentifier(), 'limit' => $limit + 1, 'repository' => $commit->getRepository()->getPHID())))->setUser($this->getViewer())->execute()); if (count($merges) > $limit) { $merges = array_slice($merges, 0, $limit); $merges_caption = pht("This commit merges more than %d changes. Only the first " . "%d are shown.\n", $limit, $limit); } if ($merges) { $merge_commits = array(); foreach ($merges as $merge) { $merge_commits[] = $merge->getAuthorName() . ': ' . $merge->getSummary(); } $body->addTextSection(pht('MERGED COMMITS'), $merges_caption . implode("\n", $merge_commits)); } } catch (ConduitException $ex) { // Log the exception into the email body $body->addTextSection(pht('MERGED COMMITS'), pht('Error generating merged commits: ') . $ex->getMessage()); } }
private function assertEmail($expect, $herald_hints) { $env = PhabricatorEnv::beginScopedEnv(); $env->overrideEnvConfig('phabricator.production-uri', 'http://test.com/'); $env->overrideEnvConfig('metamta.herald.show-hints', $herald_hints); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection('salmon'); $body->addTextSection('HEADER', "bass\ntrout\n"); $body->addHeraldSection('/xscript/'); $this->assertEqual($expect, $body->render()); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { $params = array('commit' => $this->getObject()->getCommitIdentifier(), 'callsign' => $this->getObject()->getRepository()->getCallsign()); $tags_raw = id(new ConduitCall('diffusion.tagsquery', $params))->setUser($this->getViewer())->execute(); $tags = DiffusionRepositoryTag::newFromConduit($tags_raw); if (!$tags) { return; } $tag_names = mpull($tags, 'getName'); sort($tag_names); $body->addTextSection(pht('TAGS'), implode(', ', $tag_names)); }
public function buildApplicationTransactionMailBody(PhabricatorApplicationTransaction $xaction, PhabricatorMetaMTAMailBody $body) { $params = array('contains' => $this->getObject()->getCommitIdentifier(), 'callsign' => $this->getObject()->getRepository()->getCallsign()); $branches_raw = id(new ConduitCall('diffusion.branchquery', $params))->setUser($this->getViewer())->execute(); $branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches_raw); if (!$branches) { return; } $branch_names = mpull($branches, 'getShortName'); sort($branch_names); $body->addTextSection(pht('BRANCHES'), implode(', ', $branch_names)); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { $status_accepted = ArcanistDifferentialRevisionStatus::ACCEPTED; // Show the "BRANCH" section only if there's a new diff or the revision // is "Accepted". if (!$editor->getDiffUpdateTransaction($xactions) && $this->getObject()->getStatus() != $status_accepted) { return; } $branch = $this->getBranchDescription($this->getObject()->getActiveDiff()); if ($branch === null) { return; } $body->addTextSection(pht('BRANCH'), $branch); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { $params = array('contains' => $this->getObject()->getCommitIdentifier(), 'callsign' => $this->getObject()->getRepository()->getCallsign()); try { $branches_raw = id(new ConduitCall('diffusion.branchquery', $params))->setUser($this->getViewer())->execute(); $branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches_raw); if (!$branches) { return; } $branch_names = mpull($branches, 'getShortName'); sort($branch_names); $branch_text = implode(', ', $branch_names); } catch (Exception $ex) { $branch_text = pht('<%s: %s>', get_class($ex), $ex->getMessage()); } $body->addTextSection(pht('BRANCHES'), $branch_text); }
protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $attachment_phids = $mail->getAttachments(); if (empty($attachment_phids)) { throw new PhabricatorMetaMTAReceivedMailProcessingException(MetaMTAReceivedMailStatus::STATUS_UNHANDLED_EXCEPTION, pht('Ignoring email to create files that did not include attachments.')); } $first_phid = head($attachment_phids); $mail->setRelatedPHID($first_phid); $attachment_count = count($attachment_phids); if ($attachment_count > 1) { $subject = pht('You successfully uploaded %d files.', $attachment_count); } else { $subject = pht('You successfully uploaded a file.'); } $subject_prefix = PhabricatorEnv::getEnvConfig('metamta.files.subject-prefix'); $file_uris = array(); foreach ($attachment_phids as $phid) { $file_uris[] = PhabricatorEnv::getProductionURI('/file/info/' . $phid . '/'); } $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($subject); $body->addTextSection(pht('FILE LINKS'), implode("\n", $file_uris)); id(new PhabricatorMetaMTAMail())->addTos(array($sender->getPHID()))->setSubject($subject)->setSubjectPrefix($subject_prefix)->setFrom($sender->getPHID())->setRelatedPHID($first_phid)->setBody($body->render())->saveAndSend(); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { if ($editor->getIsNewObject()) { return; } if ($editor->getIsCloseByCommit()) { return; } $xaction = $editor->getDiffUpdateTransaction($xactions); if (!$xaction) { return; } $original = id(new DifferentialDiffQuery())->setViewer($this->getViewer())->withPHIDs(array($xaction->getOldValue()))->executeOne(); if (!$original) { return; } $revision = $this->getObject(); $current = $revision->getActiveDiff(); $old_id = $original->getID(); $new_id = $current->getID(); $uri = '/' . $revision->getMonogram() . '?vs=' . $old_id . '&id=' . $new_id; $uri = PhabricatorEnv::getProductionURI($uri); $body->addTextSection(pht('CHANGES SINCE LAST UPDATE'), $uri); }
private function sendMail(PhabricatorMailTarget $target, PhabricatorRepository $repository, PhabricatorRepositoryPushEvent $event) { $task_data = $this->getTaskData(); $viewer = $target->getViewer(); $locale = PhabricatorEnv::beginScopedLocale($viewer->getTranslation()); $logs = $event->getLogs(); list($ref_lines, $ref_list) = $this->renderRefs($logs); list($commit_lines, $subject_line) = $this->renderCommits($repository, $logs, idx($task_data, 'info', array())); $ref_count = count($ref_lines); $commit_count = count($commit_lines); $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($event->getPusherPHID()))->execute(); $pusher_name = $handles[$event->getPusherPHID()]->getName(); $repo_name = $repository->getMonogram(); if ($commit_count) { $overview = pht('%s pushed %d commit(s) to %s.', $pusher_name, $commit_count, $repo_name); } else { $overview = pht('%s pushed to %s.', $pusher_name, $repo_name); } $details_uri = PhabricatorEnv::getProductionURI('/diffusion/pushlog/view/' . $event->getID() . '/'); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($overview); $body->addLinkSection(pht('DETAILS'), $details_uri); if ($commit_lines) { $body->addTextSection(pht('COMMITS'), implode("\n", $commit_lines)); } if ($ref_lines) { $body->addTextSection(pht('REFERENCES'), implode("\n", $ref_lines)); } $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix'); $parts = array(); if ($commit_count) { $parts[] = pht('%s commit(s)', $commit_count); } if ($ref_count) { $parts[] = implode(', ', $ref_list); } $parts = implode(', ', $parts); if ($subject_line) { $subject = pht('(%s) %s', $parts, $subject_line); } else { $subject = pht('(%s)', $parts); } $mail = id(new PhabricatorMetaMTAMail())->setRelatedPHID($event->getPHID())->setSubjectPrefix($prefix)->setVarySubjectPrefix(pht('[Push]'))->setSubject($subject)->setFrom($event->getPusherPHID())->setBody($body->render())->setThreadID($event->getPHID(), $is_new = true)->addHeader('Thread-Topic', $subject)->setIsBulk(true); $target->sendMail($mail); }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { $repository = $this->getObject()->getRepository(); if ($repository === null) { return; } $body->addTextSection(pht('REPOSITORY'), $repository->getMonogram() . ' ' . $repository->getName()); }
private function appendChangeDetailsForMail(PhabricatorLiskDAO $object, DifferentialDiff $diff, $patch, PhabricatorMetaMTAMailBody $body) { $section = id(new DifferentialChangeDetailMailView())->setViewer($this->getActor())->setDiff($diff)->setPatch($patch)->buildMailSection(); $header = pht('CHANGE DETAILS'); $section_text = "\n" . $section->getPlaintext(); $style = array('margin: 6px 0 12px 0;'); $section_html = phutil_tag('div', array('style' => implode(' ', $style)), $section->getHTML()); $body->addPlaintextSection($header, $section_text, false); $body->addHTMLSection($header, $section_html); }
protected function addEmailPreferenceSectionToMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorLiskDAO $object, array $xactions) { $href = PhabricatorEnv::getProductionURI('/' . $object->getMonogram() . '?settings'); $label = pht('EMAIL PREFERENCES FOR THIS ROOM'); $body->addLinkSection($label, $href); }
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); } $explicit_auditors = $this->createAuditsFromCommitMessage($commit, $data); if ($repository->getDetail('herald-disabled')) { // This just means "disable email"; audits are (mostly) idempotent. return; } $this->publishFeedStory($repository, $commit, $data); $herald_targets = $adapter->getEmailPHIDs(); $email_phids = array_unique(array_merge($explicit_auditors, $herald_targets)); if (!$email_phids) { 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 = '/herald/view/commits/'; $why_uri = '/herald/transcript/' . $xscript_id . '/'; $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit($commit); $template = new PhabricatorMetaMTAMail(); $inline_patch_text = $this->buildPatch($template, $repository, $commit); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($description); $body->addTextSection(pht('DETAILS'), $commit_uri); $body->addTextSection(pht('DIFFERENTIAL REVISION'), $differential); $body->addTextSection(pht('AFFECTED FILES'), $files); $body->addReplySection($reply_handler->getReplyHandlerInstructions()); $body->addHeraldSection($manage_uri, $why_uri); $body->addRawSection($inline_patch_text); $body = $body->render(); $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix'); $threading = PhabricatorAuditCommentEditor::getMailThreading($repository, $commit); list($thread_id, $thread_topic) = $threading; $template->setRelatedPHID($commit->getPHID()); $template->setSubject("{$commit_name}: {$name}"); $template->setSubjectPrefix($prefix); $template->setVarySubjectPrefix("[Commit]"); $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(); } }
protected function buildMailBody(PhabricatorLiskDAO $object, array $xactions) { $body = new PhabricatorMetaMTAMailBody(); $headers = array(); $comments = array(); $inline_comments = array(); foreach ($xactions as $xaction) { if ($xaction->shouldHide()) { continue; } $comment = $xaction->getComment(); switch ($xaction->getTransactionType()) { case PholioTransactionType::TYPE_INLINE: if ($comment && strlen($comment->getContent())) { $inline_comments[] = $comment; } break; case PhabricatorTransactions::TYPE_COMMENT: if ($comment && strlen($comment->getContent())) { $comments[] = $comment->getContent(); } // fallthrough // fallthrough default: $headers[] = id(clone $xaction)->setRenderingTarget('text')->getTitle(); break; } } $body->addRawSection(implode("\n", $headers)); foreach ($comments as $comment) { $body->addRawSection($comment); } if ($inline_comments) { $body->addRawSection(pht('INLINE COMMENTS')); foreach ($inline_comments as $comment) { $text = pht('Image %d: %s', $comment->getImageID(), $comment->getContent()); $body->addRawSection($text); } } $body->addTextSection(pht('MOCK DETAIL'), PhabricatorEnv::getProductionURI('/M' . $object->getID())); return $body; }
protected function buildMailBody(PhabricatorLiskDAO $object, array $xactions) { $body = new PhabricatorMetaMTAMailBody(); $body->setViewer($this->requireActor()); $this->addHeadersAndCommentsToMailBody($body, $xactions); $type_inline = DifferentialTransaction::TYPE_INLINE; $inlines = array(); foreach ($xactions as $xaction) { if ($xaction->getTransactionType() == $type_inline) { $inlines[] = $xaction; } } if ($inlines) { $body->addTextSection(pht('INLINE COMMENTS'), $this->renderInlineCommentsForMail($object, $inlines)); } $changed_uri = $this->getChangedPriorToCommitURI(); if ($changed_uri) { $body->addLinkSection(pht('CHANGED PRIOR TO COMMIT'), $changed_uri); } $this->addCustomFieldsToMailBody($body, $object, $xactions); $body->addLinkSection(pht('REVISION DETAIL'), PhabricatorEnv::getProductionURI('/D' . $object->getID())); $update_xaction = null; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case DifferentialTransaction::TYPE_UPDATE: $update_xaction = $xaction; break; } } if ($update_xaction) { $diff = $this->requireDiff($update_xaction->getNewValue(), true); $body->addTextSection(pht('AFFECTED FILES'), $this->renderAffectedFilesForMail($diff)); $config_key_inline = 'metamta.differential.inline-patches'; $config_inline = PhabricatorEnv::getEnvConfig($config_key_inline); $config_key_attach = 'metamta.differential.attach-patches'; $config_attach = PhabricatorEnv::getEnvConfig($config_key_attach); if ($config_inline || $config_attach) { $patch_section = $this->renderPatchForMail($diff); $lines = count(phutil_split_lines($patch_section->getPlaintext())); if ($config_inline && $lines <= $config_inline) { $body->addTextSection(pht('CHANGE DETAILS'), $patch_section); } if ($config_attach) { $name = pht('D%s.%s.patch', $object->getID(), $diff->getID()); $mime_type = 'text/x-patch; charset=utf-8'; $body->addAttachment(new PhabricatorMetaMTAAttachment($patch_section->getPlaintext(), $name, $mime_type)); } } } return $body; }
protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $attachments = $mail->getAttachments(); $files = array(); $errors = array(); if ($attachments) { $files = id(new PhabricatorFileQuery())->setViewer($sender)->withPHIDs($attachments)->execute(); foreach ($files as $index => $file) { if ($file->getMimeType() != 'text/plain') { $errors[] = pht('Could not parse file %s; only files with mimetype text/plain ' . 'can be parsed via email.', $file->getName()); unset($files[$index]); } } } $diffs = array(); foreach ($files as $file) { $call = new ConduitCall('differential.createrawdiff', array('diff' => $file->loadFileData())); $call->setUser($sender); try { $result = $call->execute(); $diffs[$file->getName()] = $result['uri']; } catch (Exception $e) { $errors[] = pht('Could not parse attachment %s; only attachments (and mail bodies) ' . 'generated via "diff" commands can be parsed.', $file->getName()); } } $body = $mail->getCleanTextBody(); if ($body) { $call = new ConduitCall('differential.createrawdiff', array('diff' => $body)); $call->setUser($sender); try { $result = $call->execute(); $diffs[pht('Mail Body')] = $result['uri']; } catch (Exception $e) { $errors[] = pht('Could not parse mail body; only mail bodies (and attachments) ' . 'generated via "diff" commands can be parsed.'); } } $subject_prefix = PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix'); if (count($diffs)) { $subject = pht('You successfully created %d diff(s).', count($diffs)); } else { $subject = pht('Diff creation failed; see body for %s error(s).', new PhutilNumber(count($errors))); } $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($subject); if (count($diffs)) { $text_body = ''; $html_body = array(); $body_label = pht('%s DIFF LINK(S)', new PhutilNumber(count($diffs))); foreach ($diffs as $filename => $diff_uri) { $text_body .= $filename . ': ' . $diff_uri . "\n"; $html_body[] = phutil_tag('a', array('href' => $diff_uri), $filename); $html_body[] = phutil_tag('br'); } $body->addTextSection($body_label, $text_body); $body->addHTMLSection($body_label, $html_body); } if (count($errors)) { $body_section = new PhabricatorMetaMTAMailSection(); $body_label = pht('%s ERROR(S)', new PhutilNumber(count($errors))); foreach ($errors as $error) { $body_section->addFragment($error); } $body->addTextSection($body_label, $body_section); } id(new PhabricatorMetaMTAMail())->addTos(array($sender->getPHID()))->setSubject($subject)->setSubjectPrefix($subject_prefix)->setFrom($sender->getPHID())->setBody($body->render())->saveAndSend(); }
private function buildErrorMailBody($error, PhabricatorMetaMTAReceivedMail $mail) { $original_body = $mail->getRawTextBody(); $main_body = <<<EOBODY Your request failed because an error was encoutered while processing it: ERROR: {$error} -- Original Body ------------------------------------------------------------- {$original_body} EOBODY; $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($main_body); $body->addReplySection($this->getReplyHandlerInstructions()); return $body->render(); }
private function applyHeraldRules(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $commit->attachRepository($repository); // Don't take any actions on an importing repository. Principally, this // avoids generating thousands of audits or emails when you import an // established repository on an existing install. if ($repository->isImporting()) { return; } if ($repository->getDetail('herald-disabled')) { return; } $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID()); if (!$data) { throw new PhabricatorWorkerPermanentFailureException(pht('Unable to load commit data. The data for this task is invalid ' . 'or no longer exists.')); } $adapter = id(new HeraldCommitAdapter())->setCommit($commit); $rules = id(new HeraldRuleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withContentTypes(array($adapter->getAdapterContentType()))->withDisabled(false)->needConditionsAndActions(true)->needAppliedToPHIDs(array($adapter->getPHID()))->needValidateAuthors(true)->execute(); $engine = new HeraldEngine(); $effects = $engine->applyRules($rules, $adapter); $engine->applyEffects($effects, $adapter, $rules); $xscript = $engine->getTranscript(); $audit_phids = $adapter->getAuditMap(); $cc_phids = $adapter->getAddCCMap(); if ($audit_phids || $cc_phids) { $this->createAudits($commit, $audit_phids, $cc_phids, $rules); } HarbormasterBuildable::applyBuildPlans($commit->getPHID(), $repository->getPHID(), $adapter->getBuildPlans()); $explicit_auditors = $this->createAuditsFromCommitMessage($commit, $data); $this->publishFeedStory($repository, $commit, $data); $herald_targets = $adapter->getEmailPHIDs(); $email_phids = array_unique(array_merge($explicit_auditors, array_keys($cc_phids), $herald_targets)); if (!$email_phids) { return; } $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 PhabricatorHandleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($phids)->execute(); $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.'; $limit = self::MAX_FILES_SHOWN_IN_EMAIL; $files = $adapter->loadAffectedPaths(); sort($files); if (count($files) > $limit) { array_splice($files, $limit); $files[] = '(This commit affected more than ' . $limit . ' files. ' . 'Only ' . $limit . ' are shown here and additional ones are truncated.)'; } $files = implode("\n", $files); $xscript_id = $xscript->getID(); $why_uri = '/herald/transcript/' . $xscript_id . '/'; $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit($commit); $template = new PhabricatorMetaMTAMail(); $inline_patch_text = $this->buildPatch($template, $repository, $commit); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($description); $body->addTextSection(pht('DETAILS'), $commit_uri); // TODO: This should be integrated properly once we move to // ApplicationTransactions. $field_list = PhabricatorCustomField::getObjectFields($commit, PhabricatorCustomField::ROLE_APPLICATIONTRANSACTIONS); $field_list->setViewer(PhabricatorUser::getOmnipotentUser())->readFieldsFromStorage($commit); foreach ($field_list->getFields() as $field) { try { $field->buildApplicationTransactionMailBody(new DifferentialTransaction(), $body); } catch (Exception $ex) { // Log the exception and continue. phlog($ex); } } $body->addTextSection(pht('DIFFERENTIAL REVISION'), $differential); $body->addTextSection(pht('AFFECTED FILES'), $files); $body->addReplySection($reply_handler->getReplyHandlerInstructions()); $body->addHeraldSection($why_uri); $body->addRawSection($inline_patch_text); $body = $body->render(); $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix'); $threading = PhabricatorAuditCommentEditor::getMailThreading($repository, $commit); list($thread_id, $thread_topic) = $threading; $template->setRelatedPHID($commit->getPHID()); $template->setSubject("{$commit_name}: {$name}"); $template->setSubjectPrefix($prefix); $template->setVarySubjectPrefix('[Commit]'); $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); } // TODO: We should verify that each recipient can actually see the // commit before sending them email (T603). $mails = $reply_handler->multiplexMail($template, id(new PhabricatorHandleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($email_phids)->execute(), array()); foreach ($mails as $mail) { $mail->saveAndSend(); } }
private function inlinePatch(PhabricatorMetaMTAMailBody $body, PhabricatorRepositoryCommit $commit) { if (!$this->getRawPatch()) { return; } $inline_key = 'metamta.diffusion.inline-patches'; $inline_patches = PhabricatorEnv::getEnvConfig($inline_key); if (!$inline_patches) { return; } $repository = $commit->getRepository(); $raw_patch = $this->getRawPatch(); $result = null; $len = substr_count($raw_patch, "\n"); if ($len <= $inline_patches) { // We send email as utf8, so we need to convert the text to utf8 if // we can. $encoding = $repository->getDetail('encoding', 'UTF-8'); if ($encoding) { $raw_patch = phutil_utf8_convert($raw_patch, 'UTF-8', $encoding); } $result = phutil_utf8ize($raw_patch); } if ($result) { $result = "PATCH\n\n{$result}\n"; } $body->addRawSection($result); }
private function newMailMessage(PhabricatorUser $viewer, array $events) { $events = msort($events, 'getEpoch'); $next_event = head($events); $body = new PhabricatorMetaMTAMailBody(); foreach ($events as $event) { $body->addTextSection(null, pht('%s is starting in %s minute(s), at %s.', $event->getEvent()->getName(), $event->getDisplayMinutes(), $event->getDisplayTime())); $body->addLinkSection(pht('EVENT DETAIL'), PhabricatorEnv::getProductionURI($event->getEvent()->getURI())); } $next_event = head($events)->getEvent(); $subject = $next_event->getName(); if (count($events) > 1) { $more = pht('(+%s more...)', new PhutilNumber(count($events) - 1)); $subject = "{$subject} {$more}"; } $calendar_phid = id(new PhabricatorCalendarApplication())->getPHID(); return id(new PhabricatorMetaMTAMail())->setSubject($subject)->addTos(array($viewer->getPHID()))->setSensitiveContent(false)->setFrom($calendar_phid)->setIsBulk(true)->setSubjectPrefix(pht('[Calendar]'))->setVarySubjectPrefix(pht('[Reminder]'))->setThreadID($next_event->getPHID(), false)->setRelatedPHID($next_event->getPHID())->setBody($body->render())->setHTMLBody($body->renderHTML()); }
public function send() { $email_to = array_filter(array_unique($this->to)); $question = $this->getQuestion(); $target = $this->getTarget(); $uri = PhabricatorEnv::getURI('/Q' . $question->getID()); $thread_id = $this->getThreadID(); $handles = id(new PhabricatorObjectHandleData($email_to))->loadHandles(); $reply_handler = new PonderReplyHandler(); $reply_handler->setMailReceiver($question); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($this->renderBody()); $body->addTextSection(pht('QUESTION DETAIL'), $uri); $template = id(new PhabricatorMetaMTAMail())->setSubject($this->getThreadTopic())->setSubjectPrefix($this->getSubjectPrefix())->setVarySubjectPrefix($this->renderVaryPrefix())->setFrom($target->getAuthorPHID())->setParentMessageID($this->parentMessageID)->addHeader('Thread-Topic', $this->getThreadTopic())->setThreadID($this->getThreadID(), false)->setRelatedPHID($question->getPHID())->setIsBulk(true)->setBody($body->render()); $mails = $reply_handler->multiplexMail($template, array_select_keys($handles, $email_to), array()); foreach ($mails as $mail) { $mail->saveAndSend(); } }
private function sendWaitingForApprovalEmail(PhabricatorUser $user) { $title = '[Phabricator] ' . pht('New User "%s" Awaiting Approval', $user->getUsername()); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection(pht('Newly registered user "%s" is awaiting account approval by an ' . 'administrator.', $user->getUsername())); $body->addLinkSection(pht('APPROVAL QUEUE'), PhabricatorEnv::getProductionURI('/people/query/approval/')); $body->addLinkSection(pht('DISABLE APPROVAL QUEUE'), PhabricatorEnv::getProductionURI('/config/edit/auth.require-approval/')); $admins = id(new PhabricatorPeopleQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIsAdmin(true)->execute(); if (!$admins) { return; } $mail = id(new PhabricatorMetaMTAMail())->addTos(mpull($admins, 'getPHID'))->setSubject($title)->setBody($body->render())->saveAndSend(); }
private function sendEmail($task, $transactions, $email_to, $email_cc) { $email_to = array_filter(array_unique($email_to)); $email_cc = array_filter(array_unique($email_cc)); $phids = array(); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($email_to as $phid) { $phids[$phid] = true; } foreach ($email_cc as $phid) { $phids[$phid] = true; } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $view = new ManiphestTransactionDetailView(); $view->setTransactionGroup($transactions); $view->setHandles($handles); $view->setAuxiliaryFields($this->auxiliaryFields); list($action, $main_body) = $view->renderForEmail($with_date = false); $is_create = $this->isCreate($transactions); $task_uri = PhabricatorEnv::getURI('/T' . $task->getID()); $reply_handler = $this->buildReplyHandler($task); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($main_body); if ($is_create) { $body->addTextSection(pht('TASK DESCRIPTION'), $task->getDescription()); } $body->addTextSection(pht('TASK DETAIL'), $task_uri); $body->addReplySection($reply_handler->getReplyHandlerInstructions()); $thread_id = 'maniphest-task-' . $task->getPHID(); $task_id = $task->getID(); $title = $task->getTitle(); $mailtags = $this->getMailTags($transactions); $template = id(new PhabricatorMetaMTAMail())->setSubject("T{$task_id}: {$title}")->setSubjectPrefix($this->getSubjectPrefix())->setVarySubjectPrefix("[{$action}]")->setFrom($transaction->getAuthorPHID())->setParentMessageID($this->parentMessageID)->addHeader('Thread-Topic', "T{$task_id}: " . $task->getOriginalTitle())->setThreadID($thread_id, $is_create)->setRelatedPHID($task->getPHID())->setIsBulk(true)->setMailTags($mailtags)->setBody($body->render()); $mails = $reply_handler->multiplexMail($template, array_select_keys($handles, $email_to), array_select_keys($handles, $email_cc)); foreach ($mails as $mail) { $mail->saveAndSend(); } }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { if (!$editor->getIsNewObject()) { return; } $summary = $this->getValue(); if (!strlen(trim($summary))) { return; } $body->addRemarkupSection(pht('REVISION SUMMARY'), $summary); }
private function renderMailBody(PhabricatorAuditComment $comment, $cname, PhabricatorObjectHandle $handle, PhabricatorMailReplyHandler $reply_handler, array $inline_comments) { assert_instances_of($inline_comments, 'PhabricatorInlineCommentInterface'); $commit = $this->commit; $user = $this->user; $name = $user->getUsername(); $verb = PhabricatorAuditActionConstants::getActionPastTenseVerb($comment->getAction()); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection("{$name} {$verb} commit {$cname}."); $body->addRawSection($comment->getContent()); if ($inline_comments) { $block = array(); $path_map = id(new DiffusionPathQuery())->withPathIDs(mpull($inline_comments, 'getPathID'))->execute(); $path_map = ipull($path_map, 'path', 'id'); foreach ($inline_comments as $inline) { $path = idx($path_map, $inline->getPathID()); if ($path === null) { continue; } $start = $inline->getLineNumber(); $len = $inline->getLineLength(); if ($len) { $range = $start . '-' . ($start + $len); } else { $range = $start; } $content = $inline->getContent(); $block[] = "{$path}:{$range} {$content}"; } $body->addTextSection(pht('INLINE COMMENTS'), implode("\n", $block)); } $body->addTextSection(pht('COMMIT'), PhabricatorEnv::getProductionURI($handle->getURI())); $body->addReplySection($reply_handler->getReplyHandlerInstructions()); return $body->render(); }
/** * @task mail */ protected function buildMailBody(PhabricatorLiskDAO $object, array $xactions) { $headers = array(); $comments = array(); foreach ($xactions as $xaction) { if ($xaction->shouldHideForMail($xactions)) { continue; } $header = $xaction->getTitleForMail(); if ($header !== null) { $headers[] = $header; } $comment = $xaction->getBodyForMail(); if ($comment !== null) { $comments[] = $comment; } } $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection(implode("\n", $headers)); foreach ($comments as $comment) { $body->addRawSection($comment); } if ($object instanceof PhabricatorCustomFieldInterface) { $field_list = PhabricatorCustomField::getObjectFields($object, PhabricatorCustomField::ROLE_TRANSACTIONMAIL); $field_list->setViewer($this->getActor()); $field_list->readFieldsFromStorage($object); foreach ($field_list->getFields() as $field) { $field->updateTransactionMailBody($body, $this, $xactions); } } return $body; }
/** * @task mail */ protected function addHeadersAndCommentsToMailBody(PhabricatorMetaMTAMailBody $body, array $xactions) { $headers = array(); $comments = array(); foreach ($xactions as $xaction) { if ($xaction->shouldHideForMail($xactions)) { continue; } $header = $xaction->getTitleForMail(); if ($header !== null) { $headers[] = $header; } $comment = $xaction->getBodyForMail(); if ($comment !== null) { $comments[] = $comment; } } $body->addRawSection(implode("\n", $headers)); foreach ($comments as $comment) { $body->addRemarkupSection($comment); } }
public function updateTransactionMailBody(PhabricatorMetaMTAMailBody $body, PhabricatorApplicationTransactionEditor $editor, array $xactions) { if (!$editor->getIsNewObject()) { return; } $test_plan = $this->getValue(); if (!strlen(trim($test_plan))) { return; } $body->addTextSection(pht('TEST PLAN'), $test_plan); }
/** * @task mail */ protected function addHeadersAndCommentsToMailBody(PhabricatorMetaMTAMailBody $body, array $xactions, $object_label = null, $object_href = null) { $headers = array(); $headers_html = array(); $comments = array(); $details = array(); foreach ($xactions as $xaction) { if ($xaction->shouldHideForMail($xactions)) { continue; } $header = $xaction->getTitleForMail(); if ($header !== null) { $headers[] = $header; } $header_html = $xaction->getTitleForHTMLMail(); if ($header_html !== null) { $headers_html[] = $header_html; } $comment = $xaction->getBodyForMail(); if ($comment !== null) { $comments[] = $comment; } if ($xaction->hasChangeDetailsForMail()) { $details[] = $xaction; } } $headers_text = implode("\n", $headers); $body->addRawPlaintextSection($headers_text); $headers_html = phutil_implode_html(phutil_tag('br'), $headers_html); $header_button = null; if ($object_label !== null) { $button_style = array('text-decoration: none;', 'padding: 4px 8px;', 'margin: 0 8px 8px;', 'float: right;', 'color: #464C5C;', 'font-weight: bold;', 'border-radius: 3px;', 'background-color: #F7F7F9;', 'background-image: linear-gradient(to bottom,#fff,#f1f0f1);', 'display: inline-block;', 'border: 1px solid rgba(71,87,120,.2);'); $header_button = phutil_tag('a', array('style' => implode(' ', $button_style), 'href' => $object_href), $object_label); } $xactions_style = array(); $header_action = phutil_tag('td', array(), $header_button); $header_action = phutil_tag('td', array('style' => implode(' ', $xactions_style)), array($headers_html, "\n")); $headers_html = phutil_tag('table', array(), phutil_tag('tr', array(), array($header_action, $header_button))); $body->addRawHTMLSection($headers_html); foreach ($comments as $comment) { $body->addRemarkupSection(null, $comment); } foreach ($details as $xaction) { $details = $xaction->renderChangeDetailsForMail($body->getViewer()); if ($details !== null) { $label = $this->getMailDiffSectionHeader($xaction); $body->addHTMLSection($label, $details); } } }