@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add a Twilio SMS message adapter

Summary: Ref T920. Adds a "phone number" object, an "SMS" message type, and Twilio glue.

Test Plan:
Used this test script to send myself some text messages after configuring Twilio in `cluster.mailers`.

```
<?php

require_once 'scripts/init/init-script.php';

if ($argc < 3) {
throw new Exception('usage: test.php <number> <body>');
}
$to_number = $argv[1];
$text_body = $argv[2];

$mailers = PhabricatorMetaMTAMail::newMailers(
array(
'outbound' => true,
'media' => array(
PhabricatorMailSMSMessage::MESSAGETYPE,
),
));
if (!$mailers) {
return new Aphront404Response();
}
$mailer = head($mailers);

$message = id(new PhabricatorMailSMSMessage())
->setToNumber(new PhabricatorPhoneNumber($to_number))
->setTextBody($text_body);

$mailer->sendMessage($message);
```

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T920

Differential Revision: https://secure.phabricator.com/D19971

+136
+6
src/__phutil_library_map__.php
··· 3423 3423 'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php', 3424 3424 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 3425 3425 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', 3426 + 'PhabricatorMailSMSMessage' => 'applications/metamta/message/PhabricatorMailSMSMessage.php', 3426 3427 'PhabricatorMailSMTPAdapter' => 'applications/metamta/adapter/PhabricatorMailSMTPAdapter.php', 3427 3428 'PhabricatorMailSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailSendGridAdapter.php', 3428 3429 'PhabricatorMailSendmailAdapter' => 'applications/metamta/adapter/PhabricatorMailSendmailAdapter.php', ··· 3430 3431 'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php', 3431 3432 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', 3432 3433 'PhabricatorMailTestAdapter' => 'applications/metamta/adapter/PhabricatorMailTestAdapter.php', 3434 + 'PhabricatorMailTwilioAdapter' => 'applications/metamta/adapter/PhabricatorMailTwilioAdapter.php', 3433 3435 'PhabricatorMailUtil' => 'applications/metamta/util/PhabricatorMailUtil.php', 3434 3436 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', 3435 3437 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', ··· 3851 3853 'PhabricatorPholioApplication' => 'applications/pholio/application/PhabricatorPholioApplication.php', 3852 3854 'PhabricatorPholioConfigOptions' => 'applications/pholio/config/PhabricatorPholioConfigOptions.php', 3853 3855 'PhabricatorPholioMockTestDataGenerator' => 'applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php', 3856 + 'PhabricatorPhoneNumber' => 'applications/metamta/message/PhabricatorPhoneNumber.php', 3854 3857 'PhabricatorPhortuneApplication' => 'applications/phortune/application/PhabricatorPhortuneApplication.php', 3855 3858 'PhabricatorPhortuneContentSource' => 'applications/phortune/contentsource/PhabricatorPhortuneContentSource.php', 3856 3859 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementInvoiceWorkflow.php', ··· 9257 9260 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 9258 9261 'PhabricatorMailReplyHandler' => 'Phobject', 9259 9262 'PhabricatorMailRoutingRule' => 'Phobject', 9263 + 'PhabricatorMailSMSMessage' => 'PhabricatorMailExternalMessage', 9260 9264 'PhabricatorMailSMTPAdapter' => 'PhabricatorMailAdapter', 9261 9265 'PhabricatorMailSendGridAdapter' => 'PhabricatorMailAdapter', 9262 9266 'PhabricatorMailSendmailAdapter' => 'PhabricatorMailAdapter', ··· 9264 9268 'PhabricatorMailStamp' => 'Phobject', 9265 9269 'PhabricatorMailTarget' => 'Phobject', 9266 9270 'PhabricatorMailTestAdapter' => 'PhabricatorMailAdapter', 9271 + 'PhabricatorMailTwilioAdapter' => 'PhabricatorMailAdapter', 9267 9272 'PhabricatorMailUtil' => 'Phobject', 9268 9273 'PhabricatorMainMenuBarExtension' => 'Phobject', 9269 9274 'PhabricatorMainMenuSearchView' => 'AphrontView', ··· 9768 9773 'PhabricatorPholioApplication' => 'PhabricatorApplication', 9769 9774 'PhabricatorPholioConfigOptions' => 'PhabricatorApplicationConfigOptions', 9770 9775 'PhabricatorPholioMockTestDataGenerator' => 'PhabricatorTestDataGenerator', 9776 + 'PhabricatorPhoneNumber' => 'Phobject', 9771 9777 'PhabricatorPhortuneApplication' => 'PhabricatorApplication', 9772 9778 'PhabricatorPhortuneContentSource' => 'PhabricatorContentSource', 9773 9779 'PhabricatorPhortuneManagementInvoiceWorkflow' => 'PhabricatorPhortuneManagementWorkflow',
+61
src/applications/metamta/adapter/PhabricatorMailTwilioAdapter.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailTwilioAdapter 4 + extends PhabricatorMailAdapter { 5 + 6 + const ADAPTERTYPE = 'twilio'; 7 + 8 + public function getSupportedMessageTypes() { 9 + return array( 10 + PhabricatorMailSMSMessage::MESSAGETYPE, 11 + ); 12 + } 13 + 14 + protected function validateOptions(array $options) { 15 + PhutilTypeSpec::checkMap( 16 + $options, 17 + array( 18 + 'account-sid' => 'string', 19 + 'auth-token' => 'string', 20 + 'from-number' => 'string', 21 + )); 22 + 23 + // Construct an object from the "from-number" to validate it. 24 + $number = new PhabricatorPhoneNumber($options['from-number']); 25 + } 26 + 27 + public function newDefaultOptions() { 28 + return array( 29 + 'account-sid' => null, 30 + 'auth-token' => null, 31 + 'from-number' => null, 32 + ); 33 + } 34 + 35 + public function sendMessage(PhabricatorMailExternalMessage $message) { 36 + $account_sid = $this->getOption('account-sid'); 37 + 38 + $auth_token = $this->getOption('auth-token'); 39 + $auth_token = new PhutilOpaqueEnvelope($auth_token); 40 + 41 + $from_number = $this->getOption('from-number'); 42 + $from_number = new PhabricatorPhoneNumber($from_number); 43 + 44 + $to_number = $message->getToNumber(); 45 + $text_body = $message->getTextBody(); 46 + 47 + $parameters = array( 48 + 'From' => $from_number->toE164(), 49 + 'To' => $to_number->toE164(), 50 + 'Body' => $text_body, 51 + ); 52 + 53 + $result = id(new PhabricatorTwilioFuture()) 54 + ->setAccountSID($account_sid) 55 + ->setAuthToken($auth_token) 56 + ->setMethod('Messages.json', $parameters) 57 + ->setTimeout(60) 58 + ->resolve(); 59 + } 60 + 61 + }
+15
src/applications/metamta/future/PhabricatorTwilioFuture.php
··· 7 7 private $authToken; 8 8 private $method; 9 9 private $parameters; 10 + private $timeout; 10 11 11 12 public function __construct() { 12 13 parent::__construct(null); ··· 28 29 return $this; 29 30 } 30 31 32 + public function setTimeout($timeout) { 33 + $this->timeout = $timeout; 34 + return $this; 35 + } 36 + 37 + public function getTimeout() { 38 + return $this->timeout; 39 + } 40 + 31 41 protected function getProxiedFuture() { 32 42 if (!$this->future) { 33 43 if ($this->accountSID === null) { ··· 57 67 ->setHTTPBasicAuthCredentials($this->accountSID, $this->authToken) 58 68 ->setMethod('POST') 59 69 ->addHeader('Accept', 'application/json'); 70 + 71 + $timeout = $this->getTimeout(); 72 + if ($timeout) { 73 + $future->setTimeout($timeout); 74 + } 60 75 61 76 $this->future = $future; 62 77 }
+29
src/applications/metamta/message/PhabricatorMailSMSMessage.php
··· 1 + <?php 2 + 3 + final class PhabricatorMailSMSMessage 4 + extends PhabricatorMailExternalMessage { 5 + 6 + const MESSAGETYPE = 'sms'; 7 + 8 + private $toNumber; 9 + private $textBody; 10 + 11 + public function setToNumber(PhabricatorPhoneNumber $to_number) { 12 + $this->toNumber = $to_number; 13 + return $this; 14 + } 15 + 16 + public function getToNumber() { 17 + return $this->toNumber; 18 + } 19 + 20 + public function setTextBody($text_body) { 21 + $this->textBody = $text_body; 22 + return $this; 23 + } 24 + 25 + public function getTextBody() { 26 + return $this->textBody; 27 + } 28 + 29 + }
+25
src/applications/metamta/message/PhabricatorPhoneNumber.php
··· 1 + <?php 2 + 3 + final class PhabricatorPhoneNumber 4 + extends Phobject { 5 + 6 + private $number; 7 + 8 + public function __construct($raw_number) { 9 + $number = preg_replace('/[^\d]+/', '', $raw_number); 10 + 11 + if (!preg_match('/^[1-9]\d{1,14}\z/', $number)) { 12 + throw new Exception( 13 + pht( 14 + 'Phone number ("%s") is not in a recognized format.', 15 + $raw_number)); 16 + } 17 + 18 + $this->number = $number; 19 + } 20 + 21 + public function toE164() { 22 + return '+'.$this->number; 23 + } 24 + 25 + }