mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 14:00:56 +01:00
Give "MetaMTAMail" a "message type" and support SMS
Summary: Depends on D20011. Ref T920. This change lets a "MetaMTAMail" storage object represent various different types of messages, and makes "all" the `bin/mail` stuff "totally work" with messages of non-email types. In practice, a lot of the related tooling needs some polish/refinement, but the basics work. Test Plan: Used `echo beep boop | bin/mail send-test --to epriestley --type sms` to send myself SMS. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T920 Differential Revision: https://secure.phabricator.com/D20012
This commit is contained in:
parent
596435b35e
commit
af71c51f0a
9 changed files with 174 additions and 17 deletions
|
@ -3455,6 +3455,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php',
|
||||
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
|
||||
'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php',
|
||||
'PhabricatorMailSMSEngine' => 'applications/metamta/engine/PhabricatorMailSMSEngine.php',
|
||||
'PhabricatorMailSMSMessage' => 'applications/metamta/message/PhabricatorMailSMSMessage.php',
|
||||
'PhabricatorMailSMTPAdapter' => 'applications/metamta/adapter/PhabricatorMailSMTPAdapter.php',
|
||||
'PhabricatorMailSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailSendGridAdapter.php',
|
||||
|
@ -9341,6 +9342,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorMailReplyHandler' => 'Phobject',
|
||||
'PhabricatorMailRoutingRule' => 'Phobject',
|
||||
'PhabricatorMailSMSEngine' => 'PhabricatorMailMessageEngine',
|
||||
'PhabricatorMailSMSMessage' => 'PhabricatorMailExternalMessage',
|
||||
'PhabricatorMailSMTPAdapter' => 'PhabricatorMailAdapter',
|
||||
'PhabricatorMailSendGridAdapter' => 'PhabricatorMailAdapter',
|
||||
|
|
|
@ -8,6 +8,7 @@ final class PhabricatorAuthContactNumberQuery
|
|||
private $objectPHIDs;
|
||||
private $statuses;
|
||||
private $uniqueKeys;
|
||||
private $isPrimary;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -34,6 +35,11 @@ final class PhabricatorAuthContactNumberQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withIsPrimary($is_primary) {
|
||||
$this->isPrimary = $is_primary;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorAuthContactNumber();
|
||||
}
|
||||
|
@ -80,6 +86,13 @@ final class PhabricatorAuthContactNumberQuery
|
|||
$this->uniqueKeys);
|
||||
}
|
||||
|
||||
if ($this->isPrimary !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'isPrimary = %d',
|
||||
(int)$this->isPrimary);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
75
src/applications/metamta/engine/PhabricatorMailSMSEngine.php
Normal file
75
src/applications/metamta/engine/PhabricatorMailSMSEngine.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailSMSEngine
|
||||
extends PhabricatorMailMessageEngine {
|
||||
|
||||
public function newMessage() {
|
||||
$mailer = $this->getMailer();
|
||||
$mail = $this->getMail();
|
||||
|
||||
$message = new PhabricatorMailSMSMessage();
|
||||
|
||||
$phids = $mail->getToPHIDs();
|
||||
if (!$phids) {
|
||||
$mail->setMessage(pht('Message has no "To" recipient.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($phids) > 1) {
|
||||
$mail->setMessage(pht('Message has more than one "To" recipient.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
$phid = head($phids);
|
||||
|
||||
$actor = $this->getActor($phid);
|
||||
if (!$actor) {
|
||||
$mail->setMessage(pht('Message recipient has no mailable actor.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$actor->isDeliverable()) {
|
||||
$mail->setMessage(pht('Message recipient is not deliverable.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
$omnipotent = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$contact_numbers = id(new PhabricatorAuthContactNumberQuery())
|
||||
->setViewer($omnipotent)
|
||||
->withObjectPHIDs(array($phid))
|
||||
->withStatuses(
|
||||
array(
|
||||
PhabricatorAuthContactNumber::STATUS_ACTIVE,
|
||||
))
|
||||
->withIsPrimary(true)
|
||||
->execute();
|
||||
|
||||
if (!$contact_numbers) {
|
||||
$mail->setMessage(
|
||||
pht('Message recipient has no primary contact number.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
// The database does not strictly guarantee that only one number is
|
||||
// primary, so make sure no one has monkeyed with stuff.
|
||||
if (count($contact_numbers) > 1) {
|
||||
$mail->setMessage(
|
||||
pht('Message recipient has more than one primary contact number.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
$contact_number = head($contact_numbers);
|
||||
$contact_number = $contact_number->getContactNumber();
|
||||
$to_number = new PhabricatorPhoneNumber($contact_number);
|
||||
$message->setToNumber($to_number);
|
||||
|
||||
$body = $mail->getBody();
|
||||
if ($body !== null) {
|
||||
$message->setTextBody($body);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,8 +7,7 @@ final class PhabricatorMailManagementListOutboundWorkflow
|
|||
$this
|
||||
->setName('list-outbound')
|
||||
->setSynopsis(pht('List outbound messages sent by Phabricator.'))
|
||||
->setExamples(
|
||||
'**list-outbound**')
|
||||
->setExamples('**list-outbound**')
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
|
@ -39,6 +38,7 @@ final class PhabricatorMailManagementListOutboundWorkflow
|
|||
->addColumn('id', array('title' => pht('ID')))
|
||||
->addColumn('encrypt', array('title' => pht('#')))
|
||||
->addColumn('status', array('title' => pht('Status')))
|
||||
->addColumn('type', array('title' => pht('Type')))
|
||||
->addColumn('subject', array('title' => pht('Subject')));
|
||||
|
||||
foreach (array_reverse($mails) as $mail) {
|
||||
|
@ -48,6 +48,7 @@ final class PhabricatorMailManagementListOutboundWorkflow
|
|||
'id' => $mail->getID(),
|
||||
'encrypt' => ($mail->getMustEncrypt() ? '#' : ' '),
|
||||
'status' => PhabricatorMailOutboundStatus::getStatusName($status),
|
||||
'type' => $mail->getMessageType(),
|
||||
'subject' => $mail->getSubject(),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -60,6 +60,12 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
'name' => 'bulk',
|
||||
'help' => pht('Send with bulk headers.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'type',
|
||||
'param' => 'message-type',
|
||||
'help' => pht(
|
||||
'Send the specified type of message (email, sms, ...).'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -67,6 +73,20 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
$console = PhutilConsole::getConsole();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$type = $args->getArg('type');
|
||||
if (!strlen($type)) {
|
||||
$type = PhabricatorMailEmailMessage::MESSAGETYPE;
|
||||
}
|
||||
|
||||
$type_map = PhabricatorMailExternalMessage::getAllMessageTypes();
|
||||
if (!isset($type_map[$type])) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Message type "%s" is unknown, supported message types are: %s.',
|
||||
$type,
|
||||
implode(', ', array_keys($type_map))));
|
||||
}
|
||||
|
||||
$from = $args->getArg('from');
|
||||
if ($from) {
|
||||
$user = id(new PhabricatorPeopleQuery())
|
||||
|
@ -86,9 +106,8 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
if (!$tos && !$ccs) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify one or more users to send mail to with `%s` and `%s`.',
|
||||
'--to',
|
||||
'--cc'));
|
||||
'Specify one or more users to send a message to with "--to" and/or '.
|
||||
'"--cc".'));
|
||||
}
|
||||
|
||||
$names = array_merge($tos, $ccs);
|
||||
|
@ -166,26 +185,32 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
$mail->setFrom($from->getPHID());
|
||||
}
|
||||
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(
|
||||
array(
|
||||
'media' => array($type),
|
||||
'outbound' => true,
|
||||
));
|
||||
$mailers = mpull($mailers, null, 'getKey');
|
||||
|
||||
if (!$mailers) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'No configured mailers support outbound messages of type "%s".',
|
||||
$type));
|
||||
}
|
||||
|
||||
$mailer_key = $args->getArg('mailer');
|
||||
if ($mailer_key !== null) {
|
||||
$mailers = PhabricatorMetaMTAMail::newMailers(array());
|
||||
|
||||
$mailers = mpull($mailers, null, 'getKey');
|
||||
if (!isset($mailers[$mailer_key])) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Mailer key ("%s") is not configured. Available keys are: %s.',
|
||||
'Mailer key ("%s") is not configured, or does not support '.
|
||||
'outbound messages of type "%s". Available mailers are: %s.',
|
||||
$mailer_key,
|
||||
$type,
|
||||
implode(', ', array_keys($mailers))));
|
||||
}
|
||||
|
||||
if (!$mailers[$mailer_key]->getSupportsOutbound()) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Mailer ("%s") is not configured to support outbound mail.',
|
||||
$mailer_key));
|
||||
}
|
||||
|
||||
$mail->setTryMailers(array($mailer_key));
|
||||
}
|
||||
|
||||
|
@ -197,6 +222,8 @@ final class PhabricatorMailManagementSendTestWorkflow
|
|||
$mail->addAttachment($file);
|
||||
}
|
||||
|
||||
$mail->setMessageType($type);
|
||||
|
||||
PhabricatorWorker::setRunAllTasksInProcess(true);
|
||||
$mail->save();
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ final class PhabricatorMailEmailMessage
|
|||
private $textBody;
|
||||
private $htmlBody;
|
||||
|
||||
public function newMailMessageEngine() {
|
||||
return new PhabricatorMailEmailEngine();
|
||||
}
|
||||
|
||||
public function setFromAddress(PhutilEmailAddress $from_address) {
|
||||
$this->fromAddress = $from_address;
|
||||
return $this;
|
||||
|
|
|
@ -7,4 +7,11 @@ abstract class PhabricatorMailExternalMessage
|
|||
return $this->getPhobjectClassConstant('MESSAGETYPE');
|
||||
}
|
||||
|
||||
final public static function getAllMessageTypes() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->setUniqueMethod('getMessageType')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ final class PhabricatorMailSMSMessage
|
|||
private $toNumber;
|
||||
private $textBody;
|
||||
|
||||
public function newMailMessageEngine() {
|
||||
return new PhabricatorMailSMSEngine();
|
||||
}
|
||||
|
||||
public function setToNumber(PhabricatorPhoneNumber $to_number) {
|
||||
$this->toNumber = $to_number;
|
||||
return $this;
|
||||
|
|
|
@ -400,6 +400,18 @@ final class PhabricatorMetaMTAMail
|
|||
return $this->getParam('cc', array());
|
||||
}
|
||||
|
||||
public function setMessageType($message_type) {
|
||||
return $this->setParam('message.type', $message_type);
|
||||
}
|
||||
|
||||
public function getMessageType() {
|
||||
return $this->getParam(
|
||||
'message.type',
|
||||
PhabricatorMailEmailMessage::MESSAGETYPE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Force delivery of a message, even if recipients have preferences which
|
||||
* would otherwise drop the message.
|
||||
|
@ -529,6 +541,9 @@ final class PhabricatorMetaMTAMail
|
|||
$mailers = self::newMailers(
|
||||
array(
|
||||
'outbound' => true,
|
||||
'media' => array(
|
||||
$this->getMessageType(),
|
||||
),
|
||||
));
|
||||
|
||||
$try_mailers = $this->getParam('mailers.try');
|
||||
|
@ -699,10 +714,19 @@ final class PhabricatorMetaMTAMail
|
|||
$file->attachToObject($this->getPHID());
|
||||
}
|
||||
|
||||
$type_map = PhabricatorMailExternalMessage::getAllMessageTypes();
|
||||
$type = idx($type_map, $this->getMessageType());
|
||||
if (!$type) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to send message with unknown message type "%s".',
|
||||
$type));
|
||||
}
|
||||
|
||||
$exceptions = array();
|
||||
foreach ($mailers as $mailer) {
|
||||
try {
|
||||
$message = id(new PhabricatorMailEmailEngine())
|
||||
$message = $type->newMailMessageEngine()
|
||||
->setMailer($mailer)
|
||||
->setMail($this)
|
||||
->setActors($actors)
|
||||
|
|
Loading…
Reference in a new issue