diff --git a/resources/sql/autopatches/20190101.sms.01.drop.sql b/resources/sql/autopatches/20190101.sms.01.drop.sql new file mode 100644 index 0000000000..b233f7ab78 --- /dev/null +++ b/resources/sql/autopatches/20190101.sms.01.drop.sql @@ -0,0 +1 @@ +DROP TABLE {$NAMESPACE}_metamta.sms; diff --git a/scripts/sms/manage_sms.php b/scripts/sms/manage_sms.php deleted file mode 100755 index 25a41d5d48..0000000000 --- a/scripts/sms/manage_sms.php +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -setTagline(pht('manage SMS')); -$args->setSynopsis(<<parseStandardArguments(); - -$workflows = id(new PhutilClassMapQuery()) - ->setAncestorClass('PhabricatorSMSManagementWorkflow') - ->execute(); -$workflows[] = new PhutilHelpArgumentWorkflow(); -$args->parseWorkflows($workflows); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f96f2f8583..5b9e818765 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4239,19 +4239,6 @@ phutil_register_library_map(array( 'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php', 'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', - 'PhabricatorSMS' => 'infrastructure/sms/storage/PhabricatorSMS.php', - 'PhabricatorSMSConfigOptions' => 'applications/config/option/PhabricatorSMSConfigOptions.php', - 'PhabricatorSMSDAO' => 'infrastructure/sms/storage/PhabricatorSMSDAO.php', - 'PhabricatorSMSDemultiplexWorker' => 'infrastructure/sms/worker/PhabricatorSMSDemultiplexWorker.php', - 'PhabricatorSMSImplementationAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php', - 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php', - 'PhabricatorSMSImplementationTwilioAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php', - 'PhabricatorSMSManagementListOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php', - 'PhabricatorSMSManagementSendTestWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php', - 'PhabricatorSMSManagementShowOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php', - 'PhabricatorSMSManagementWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php', - 'PhabricatorSMSSendWorker' => 'infrastructure/sms/worker/PhabricatorSMSSendWorker.php', - 'PhabricatorSMSWorker' => 'infrastructure/sms/worker/PhabricatorSMSWorker.php', 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', 'PhabricatorSSHKeyGenerator' => 'infrastructure/util/PhabricatorSSHKeyGenerator.php', 'PhabricatorSSHKeysSettingsPanel' => 'applications/settings/panel/PhabricatorSSHKeysSettingsPanel.php', @@ -10269,19 +10256,6 @@ phutil_register_library_map(array( 'PhabricatorResourceSite' => 'PhabricatorSite', 'PhabricatorRobotsController' => 'PhabricatorController', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', - 'PhabricatorSMS' => 'PhabricatorSMSDAO', - 'PhabricatorSMSConfigOptions' => 'PhabricatorApplicationConfigOptions', - 'PhabricatorSMSDAO' => 'PhabricatorLiskDAO', - 'PhabricatorSMSDemultiplexWorker' => 'PhabricatorSMSWorker', - 'PhabricatorSMSImplementationAdapter' => 'Phobject', - 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'PhabricatorSMSImplementationAdapter', - 'PhabricatorSMSImplementationTwilioAdapter' => 'PhabricatorSMSImplementationAdapter', - 'PhabricatorSMSManagementListOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', - 'PhabricatorSMSManagementSendTestWorkflow' => 'PhabricatorSMSManagementWorkflow', - 'PhabricatorSMSManagementShowOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', - 'PhabricatorSMSManagementWorkflow' => 'PhabricatorManagementWorkflow', - 'PhabricatorSMSSendWorker' => 'PhabricatorSMSWorker', - 'PhabricatorSMSWorker' => 'PhabricatorWorker', 'PhabricatorSQLPatchList' => 'Phobject', 'PhabricatorSSHKeyGenerator' => 'Phobject', 'PhabricatorSSHKeysSettingsPanel' => 'PhabricatorSettingsPanel', diff --git a/src/applications/config/option/PhabricatorSMSConfigOptions.php b/src/applications/config/option/PhabricatorSMSConfigOptions.php deleted file mode 100644 index 08f2e50ee1..0000000000 --- a/src/applications/config/option/PhabricatorSMSConfigOptions.php +++ /dev/null @@ -1,60 +0,0 @@ -newOption( - 'sms.default-sender', - 'string', - null) - ->setDescription(pht('Default "from" number.')) - ->addExample('8675309', 'Jenny still has this number') - ->addExample('18005555555', 'Maybe not a real number'), - $this->newOption( - 'sms.default-adapter', - 'class', - null) - ->setBaseClass('PhabricatorSMSImplementationAdapter') - ->setSummary(pht('Control how SMS is sent.')) - ->setDescription($adapter_description), - $this->newOption( - 'twilio.account-sid', - 'string', - null) - ->setDescription(pht('Account ID on Twilio service.')) - ->setLocked(true) - ->addExample('gf5kzccfn2sfknpnadvz7kokv6nz5v', pht('30 characters')), - $this->newOption( - 'twilio.auth-token', - 'string', - null) - ->setDescription(pht('Authorization token from Twilio service.')) - ->setHidden(true) - ->addExample('f3jsi4i67wiwt6w54hf2zwvy3fjf5h', pht('30 characters')), - ); - } - -} diff --git a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php b/src/infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php deleted file mode 100644 index 84325774ff..0000000000 --- a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php +++ /dev/null @@ -1,88 +0,0 @@ -fromNumber = $number; - return $this; - } - - public function getFrom() { - return $this->fromNumber; - } - - public function setTo($number) { - $this->toNumber = $number; - return $this; - } - - public function getTo() { - return $this->toNumber; - } - - public function setBody($body) { - $this->body = $body; - return $this; - } - - public function getBody() { - return $this->body; - } - - /** - * 16 characters or less, to be used in database columns and exposed - * to administrators during configuration directly. - */ - abstract public function getProviderShortName(); - - /** - * Send the message. Generally, this means connecting to some service and - * handing data to it. SMS APIs are generally asynchronous, so truly - * determining success or failure is probably impossible synchronously. - * - * That said, if the adapter determines that the SMS will never be - * deliverable, or there is some other known failure, it should throw - * an exception. - * - * @return null - */ - abstract public function send(); - - /** - * Most (all?) SMS APIs are asynchronous, but some do send back some - * initial information. Use this hook to determine what the updated - * sentStatus should be and what the provider is using for an SMS ID, - * as well as throw exceptions if there are any failures. - * - * @return array Tuple of ($sms_id and $sent_status) - */ - abstract public function getSMSDataFromResult($result); - - /** - * Due to the asynchronous nature of sending SMS messages, it can be - * necessary to poll the provider regarding the sent status of a given - * sms. - * - * For now, this *MUST* be implemented and *MUST* work. - */ - abstract public function pollSMSSentStatus(PhabricatorSMS $sms); - - /** - * Convenience function to handle sending an SMS. - */ - public static function sendSMS(array $to_numbers, $body) { - PhabricatorWorker::scheduleTask( - 'PhabricatorSMSDemultiplexWorker', - array( - 'toNumbers' => $to_numbers, - 'body' => $body, - ), - array( - 'priority' => PhabricatorWorker::PRIORITY_ALERTS, - )); - } -} diff --git a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php b/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php deleted file mode 100644 index 317ea7146b..0000000000 --- a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php +++ /dev/null @@ -1,31 +0,0 @@ -getID()) { - return PhabricatorSMS::STATUS_SENT; - } - return PhabricatorSMS::STATUS_SENT_UNCONFIRMED; - } - -} diff --git a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php b/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php deleted file mode 100644 index 56a91f7caf..0000000000 --- a/src/infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php +++ /dev/null @@ -1,99 +0,0 @@ -buildClient(); - - try { - $message = $client->account->sms_messages->create( - $this->formatNumberForSMS($this->getFrom()), - $this->formatNumberForSMS($this->getTo()), - $this->getBody(), - array()); - } catch (Services_Twilio_RestException $e) { - $message = sprintf( - 'HTTP Code %d: %s', - $e->getStatus(), - $e->getMessage()); - - // Twilio tries to provide a link to more specific details if they can. - if ($e->getInfo()) { - $message .= sprintf(' For more information, see %s.', $e->getInfo()); - } - throw new PhabricatorWorkerPermanentFailureException($message); - } - return $message; - } - - public function getSMSDataFromResult($result) { - return array($result->sid, $this->getSMSStatus($result->status)); - } - - public function pollSMSSentStatus(PhabricatorSMS $sms) { - $client = $this->buildClient(); - $message = $client->account->messages->get($sms->getProviderSMSID()); - - return $this->getSMSStatus($message->status); - } - - /** - * See https://www.twilio.com/docs/api/rest/sms#sms-status-values. - */ - private function getSMSStatus($twilio_status) { - switch ($twilio_status) { - case 'failed': - $status = PhabricatorSMS::STATUS_FAILED; - break; - case 'sent': - $status = PhabricatorSMS::STATUS_SENT; - break; - case 'sending': - case 'queued': - default: - $status = PhabricatorSMS::STATUS_SENT_UNCONFIRMED; - break; - } - return $status; - } - - /** - * We expect numbers to be plainly entered - i.e. the preg_replace here - * should do nothing - but try hard to format anyway. - * - * Twilio uses E164 format, e.g. +15551234567 - */ - private function formatNumberForSMS($number) { - $number = preg_replace('/[^0-9]/', '', $number); - $first_char = substr($number, 0, 1); - switch ($first_char) { - case '1': - $prepend = '+'; - break; - default: - $prepend = '+1'; - break; - } - return $prepend.$number; - } - -} diff --git a/src/infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php b/src/infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php deleted file mode 100644 index 5766201667..0000000000 --- a/src/infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php +++ /dev/null @@ -1,54 +0,0 @@ -setName('list-outbound') - ->setSynopsis(pht('List outbound SMS messages sent by Phabricator.')) - ->setExamples('**list-outbound**') - ->setArguments( - array( - array( - 'name' => 'limit', - 'param' => 'N', - 'default' => 100, - 'help' => pht( - 'Show a specific number of SMS messages (default 100).'), - ), - )); - } - - public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); - $viewer = $this->getViewer(); - - $sms_messages = id(new PhabricatorSMS())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d', - $args->getArg('limit')); - - if (!$sms_messages) { - $console->writeErr("%s\n", pht('No sent SMS.')); - return 0; - } - - $table = id(new PhutilConsoleTable()) - ->setShowHeader(false) - ->addColumn('id', array('title' => pht('ID'))) - ->addColumn('status', array('title' => pht('Status'))) - ->addColumn('recv', array('title' => pht('Recipient'))); - - foreach (array_reverse($sms_messages) as $sms) { - $table->addRow(array( - 'id' => $sms->getID(), - 'status' => $sms->getSendStatus(), - 'recv' => $sms->getToNumber(), - )); - } - - $table->draw(); - return 0; - } - -} diff --git a/src/infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php b/src/infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php deleted file mode 100644 index 7bb4573099..0000000000 --- a/src/infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php +++ /dev/null @@ -1,47 +0,0 @@ -setName('send-test') - ->setSynopsis( - pht( - 'Simulate sending an SMS. This may be useful to test your SMS '. - 'configuration, or while developing new SMS adapters.')) - ->setExamples("**send-test** --to 12345678 --body 'pizza time yet?'") - ->setArguments( - array( - array( - 'name' => 'to', - 'param' => 'number', - 'help' => pht('Send SMS "To:" the specified number.'), - 'repeat' => true, - ), - array( - 'name' => 'body', - 'param' => 'text', - 'help' => pht('Send SMS with the specified body.'), - ), - )); - } - - public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); - $viewer = $this->getViewer(); - - $tos = $args->getArg('to'); - $body = $args->getArg('body'); - - PhabricatorWorker::setRunAllTasksInProcess(true); - PhabricatorSMSImplementationAdapter::sendSMS($tos, $body); - - $console->writeErr( - "%s\n\n phabricator/ $ ./bin/sms list-outbound \n\n", - pht( - 'Send completed! You can view the list of SMS messages sent by '. - 'running this command:')); - } - -} diff --git a/src/infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php b/src/infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php deleted file mode 100644 index 19a306b6da..0000000000 --- a/src/infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php +++ /dev/null @@ -1,72 +0,0 @@ -setName('show-outbound') - ->setSynopsis(pht('Show diagnostic details about outbound SMS.')) - ->setExamples( - '**show-outbound** --id 1 --id 2') - ->setArguments( - array( - array( - 'name' => 'id', - 'param' => 'id', - 'help' => pht('Show details about outbound SMS with given ID.'), - 'repeat' => true, - ), - )); - } - - public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); - - $ids = $args->getArg('id'); - if (!$ids) { - throw new PhutilArgumentUsageException( - pht( - "Use the '%s' flag to specify one or more SMS messages to show.", - '--id')); - } - - $messages = id(new PhabricatorSMS())->loadAllWhere( - 'id IN (%Ld)', - $ids); - - if ($ids) { - $ids = array_fuse($ids); - $missing = array_diff_key($ids, $messages); - if ($missing) { - throw new PhutilArgumentUsageException( - pht( - 'Some specified SMS messages do not exist: %s', - implode(', ', array_keys($missing)))); - } - } - - $last_key = last_key($messages); - foreach ($messages as $message_key => $message) { - $info = array(); - - $info[] = pht('PROPERTIES'); - $info[] = pht('ID: %d', $message->getID()); - $info[] = pht('Status: %s', $message->getSendStatus()); - $info[] = pht('To: %s', $message->getToNumber()); - $info[] = pht('From: %s', $message->getFromNumber()); - - $info[] = null; - $info[] = pht('BODY'); - $info[] = $message->getBody(); - $info[] = null; - - $console->writeOut('%s', implode("\n", $info)); - - if ($message_key != $last_key) { - $console->writeOut("\n%s\n\n", str_repeat('-', 80)); - } - } - } - -} diff --git a/src/infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php b/src/infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php deleted file mode 100644 index 64bc65e2e5..0000000000 --- a/src/infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php +++ /dev/null @@ -1,4 +0,0 @@ -setBody($body) - ->setSendStatus(self::STATUS_UNSENT) - ->setProviderShortName(self::SHORTNAME_PLACEHOLDER) - ->setProviderSMSID(Filesystem::readRandomCharacters(40)); - } - - protected function getConfiguration() { - return array( - self::CONFIG_COLUMN_SCHEMA => array( - 'providerShortName' => 'text16', - 'providerSMSID' => 'text40', - 'toNumber' => 'text20', - 'fromNumber' => 'text20?', - 'body' => 'text', - 'sendStatus' => 'text16?', - ), - self::CONFIG_KEY_SCHEMA => array( - 'key_provider' => array( - 'columns' => array('providerSMSID', 'providerShortName'), - 'unique' => true, - ), - ), - ) + parent::getConfiguration(); - } - - public function getTableName() { - // Slightly non-standard, but otherwise this class needs "MetaMTA" in its - // name. :/ - return 'sms'; - } - - public function hasBeenSentAtLeastOnce() { - return ($this->getProviderShortName() != - self::SHORTNAME_PLACEHOLDER); - } -} diff --git a/src/infrastructure/sms/storage/PhabricatorSMSDAO.php b/src/infrastructure/sms/storage/PhabricatorSMSDAO.php deleted file mode 100644 index 90ed3dee14..0000000000 --- a/src/infrastructure/sms/storage/PhabricatorSMSDAO.php +++ /dev/null @@ -1,11 +0,0 @@ -getTaskData(); - - $to_numbers = idx($task_data, 'toNumbers'); - if (!$to_numbers) { - // If we don't have any to numbers, don't send any sms. - return; - } - - foreach ($to_numbers as $number) { - // NOTE: we will set the fromNumber and the proper provider data - // in the `PhabricatorSMSSendWorker`. - $sms = PhabricatorSMS::initializeNewSMS($task_data['body']); - $sms->setToNumber($number); - $sms->save(); - $this->queueTask( - 'PhabricatorSMSSendWorker', - array( - 'smsID' => $sms->getID(), - )); - } - } - -} diff --git a/src/infrastructure/sms/worker/PhabricatorSMSSendWorker.php b/src/infrastructure/sms/worker/PhabricatorSMSSendWorker.php deleted file mode 100644 index d7fefe25d0..0000000000 --- a/src/infrastructure/sms/worker/PhabricatorSMSSendWorker.php +++ /dev/null @@ -1,85 +0,0 @@ -getTaskData(); - - $sms = id(new PhabricatorSMS()) - ->loadOneWhere('id = %d', $task_data['smsID']); - - if (!$sms) { - throw new PhabricatorWorkerPermanentFailureException( - pht('SMS object was not found.')); - } - - // this has the potential to be updated asynchronously - if ($sms->getSendStatus() == PhabricatorSMS::STATUS_SENT) { - return; - } - - $adapter = PhabricatorEnv::getEnvConfig('sms.default-adapter'); - $adapter = newv($adapter, array()); - if ($sms->hasBeenSentAtLeastOnce()) { - $up_to_date_status = $adapter->pollSMSSentStatus($sms); - if ($up_to_date_status) { - $sms->setSendStatus($up_to_date_status); - if ($up_to_date_status == PhabricatorSMS::STATUS_SENT) { - $sms->save(); - return; - } - } - // TODO - re-jigger this so we can try if appropos (e.g. rate limiting) - return; - } - - $from_number = PhabricatorEnv::getEnvConfig('sms.default-sender'); - // always set the from number if we get this far in case of configuration - // changes. - $sms->setFromNumber($from_number); - - $adapter->setTo($sms->getToNumber()); - $adapter->setFrom($sms->getFromNumber()); - $adapter->setBody($sms->getBody()); - // give the provider name the same treatment as phone number - $sms->setProviderShortName($adapter->getProviderShortName()); - - if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { - $sms->setSendStatus(PhabricatorSMS::STATUS_FAILED_PERMANENTLY); - $sms->save(); - throw new PhabricatorWorkerPermanentFailureException( - pht( - 'Phabricator is running in silent mode. See `%s` '. - 'in the configuration to change this setting.', - 'phabricator.silent')); - } - - try { - $result = $adapter->send(); - list($sms_id, $sent_status) = $adapter->getSMSDataFromResult($result); - } catch (PhabricatorWorkerPermanentFailureException $e) { - $sms->setSendStatus(PhabricatorSMS::STATUS_FAILED_PERMANENTLY); - $sms->save(); - throw $e; - } catch (Exception $e) { - $sms->setSendStatus(PhabricatorSMS::STATUS_FAILED_PERMANENTLY); - $sms->save(); - throw new PhabricatorWorkerPermanentFailureException( - $e->getMessage()); - } - $sms->setProviderSMSID($sms_id); - $sms->setSendStatus($sent_status); - $sms->save(); - } - -} diff --git a/src/infrastructure/sms/worker/PhabricatorSMSWorker.php b/src/infrastructure/sms/worker/PhabricatorSMSWorker.php deleted file mode 100644 index 7b8f851eaa..0000000000 --- a/src/infrastructure/sms/worker/PhabricatorSMSWorker.php +++ /dev/null @@ -1,4 +0,0 @@ -