Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15468909
D8117.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D8117.diff
View Options
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1648,6 +1648,7 @@
'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php',
'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php',
'PhabricatorMetaMTAMailingList' => 'applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php',
+ 'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php',
'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php',
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php',
'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php',
@@ -4325,6 +4326,7 @@
0 => 'PhabricatorMetaMTADAO',
1 => 'PhabricatorPolicyInterface',
),
+ 'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery',
'PhabricatorMetaMTAPermanentFailureException' => 'Exception',
'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception',
Index: src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
===================================================================
--- /dev/null
+++ src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Expands aggregate mail recipients into their component mailables. For
+ * example, a project currently expands into all of its members.
+ */
+final class PhabricatorMetaMTAMemberQuery extends PhabricatorQuery {
+
+ private $phids = array();
+ private $viewer;
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function withPHIDs(array $phids) {
+ $this->phids = $phids;
+ return $this;
+ }
+
+ public function execute() {
+ $phids = array_fuse($this->phids);
+ $actors = array();
+ $type_map = array();
+ foreach ($phids as $phid) {
+ $type_map[phid_get_type($phid)][] = $phid;
+ }
+
+ // TODO: Generalize this somewhere else.
+
+ $results = array();
+ foreach ($type_map as $type => $phids) {
+ switch ($type) {
+ case PhabricatorProjectPHIDTypeProject::TYPECONST:
+ // TODO: For now, project members are always on the "mailing list"
+ // implied by the project, but we should differentiate members and
+ // subscribers (i.e., allow you to unsubscribe from mail about
+ // a project).
+
+ $projects = id(new PhabricatorProjectQuery())
+ ->setViewer($this->getViewer())
+ ->needMembers(true)
+ ->withPHIDs($phids)
+ ->execute();
+
+ $projects = mpull($projects, null, 'getPHID');
+ foreach ($phids as $phid) {
+ $project = idx($projects, $phid);
+ if (!$project) {
+ $results[$phid] = array();
+ } else {
+ $results[$phid] = $project->getMemberPHIDs();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return $results;
+ }
+
+}
Index: src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
===================================================================
--- src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
+++ src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
@@ -198,6 +198,15 @@
}
}
+ // TODO: This is pretty messy. We should really be doing all of this
+ // multiplexing in the task queue, but that requires significant rewriting
+ // in the general case. ApplicationTransactions can do it fairly easily,
+ // but other mail sites currently can not, so we need to support this
+ // junky version until they catch up and we can swap things over.
+
+ $to_handles = $this->expandRecipientHandles($to_handles);
+ $cc_handles = $this->expandRecipientHandles($cc_handles);
+
$tos = mpull($to_handles, null, 'getPHID');
$ccs = mpull($cc_handles, null, 'getPHID');
@@ -219,6 +228,8 @@
$body .= $this->getRecipientsSummary($to_handles, $cc_handles);
foreach ($recipients as $phid => $recipient) {
+
+
$mail = clone $mail_template;
if (isset($to_handles[$phid])) {
$mail->addTos(array($phid));
@@ -332,4 +343,32 @@
return rtrim($body);
}
+ private function expandRecipientHandles(array $handles) {
+ if (!$handles) {
+ return array();
+ }
+
+ $phids = mpull($handles, 'getPHID');
+ $map = id(new PhabricatorMetaMTAMemberQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($phids)
+ ->execute();
+
+ $results = array();
+ foreach ($phids as $phid) {
+ if (isset($map[$phid])) {
+ foreach ($map[$phid] as $expanded_phid) {
+ $results[$expanded_phid] = $expanded_phid;
+ }
+ } else {
+ $results[$phid] = $phid;
+ }
+ }
+
+ return id(new PhabricatorHandleQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($results)
+ ->execute();
+ }
+
}
Index: src/applications/metamta/storage/PhabricatorMetaMTAMail.php
===================================================================
--- src/applications/metamta/storage/PhabricatorMetaMTAMail.php
+++ src/applications/metamta/storage/PhabricatorMetaMTAMail.php
@@ -19,6 +19,7 @@
private $excludePHIDs = array();
private $overrideNoSelfMail = false;
+ private $recipientExpansionMap;
public function __construct() {
@@ -379,7 +380,8 @@
$mailer->addReplyTo($value, $reply_to_name);
break;
case 'to':
- $to_actors = array_select_keys($deliverable_actors, $value);
+ $to_phids = $this->expandRecipients($value);
+ $to_actors = array_select_keys($deliverable_actors, $to_phids);
$add_to = array_merge(
$add_to,
mpull($to_actors, 'getEmailAddress'));
@@ -388,7 +390,8 @@
$add_to = array_merge($add_to, $value);
break;
case 'cc':
- $cc_actors = array_select_keys($deliverable_actors, $value);
+ $cc_phids = $this->expandRecipients($value);
+ $cc_actors = array_select_keys($deliverable_actors, $cc_phids);
$add_cc = array_merge(
$add_cc,
mpull($cc_actors, 'getEmailAddress'));
@@ -685,9 +688,54 @@
$this->getToPHIDs(),
$this->getCcPHIDs());
+ $this->loadRecipientExpansions($actor_phids);
+ $actor_phids = $this->expandRecipients($actor_phids);
+
return $this->loadActors($actor_phids);
}
+ private function loadRecipientExpansions(array $phids) {
+ $expansions = id(new PhabricatorMetaMTAMemberQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs($phids)
+ ->execute();
+
+ $this->recipientExpansionMap = $expansions;
+
+ return $this;
+ }
+
+ /**
+ * Expand a list of recipient PHIDs (possibly including aggregate recipients
+ * like projects) into a deaggregated list of individual recipient PHIDs.
+ * For example, this will expand project PHIDs into a list of the project's
+ * members.
+ *
+ * @param list<phid> List of recipient PHIDs, possibly including aggregate
+ * recipients.
+ * @return list<phid> Deaggregated list of mailable recipients.
+ */
+ private function expandRecipients(array $phids) {
+ if ($this->recipientExpansionMap === null) {
+ throw new Exception(
+ pht(
+ 'Call loadRecipientExpansions() before expandRecipients()!'));
+ }
+
+ $results = array();
+ foreach ($phids as $phid) {
+ if (!isset($this->recipientExpansionMap[$phid])) {
+ $results[$phid] = $phid;
+ } else {
+ foreach ($this->recipientExpansionMap[$phid] as $recipient_phid) {
+ $results[$recipient_phid] = $recipient_phid;
+ }
+ }
+ }
+
+ return array_keys($results);
+ }
+
private function filterDeliverableActors(array $actors) {
assert_instances_of($actors, 'PhabricatorMetaMTAActor');
$deliverable_actors = array();
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 5, 7:38 AM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7706768
Default Alt Text
D8117.diff (8 KB)
Attached To
Mode
D8117: Expand aggregate email recipients prior to multiplexing
Attached
Detach File
Event Timeline
Log In to Comment