diff --git a/resources/sql/autopatches/20150115.applicationemails.sql b/resources/sql/autopatches/20150115.applicationemails.sql new file mode 100644 index 0000000000..a39bd16534 --- /dev/null +++ b/resources/sql/autopatches/20150115.applicationemails.sql @@ -0,0 +1,12 @@ +CREATE TABLE {$NAMESPACE}_metamta.metamta_applicationemail ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARBINARY(64) NOT NULL, + applicationPHID VARBINARY(64) NOT NULL, + address VARCHAR(128) NOT NULL COLLATE {$COLLATE_SORT}, + configData LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + KEY `key_application` (applicationPHID), + UNIQUE KEY `key_address` (address), + UNIQUE KEY `key_phid` (phid) +) ENGINE=MyISAM DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20150116.maniphestapplicationemails.php b/resources/sql/autopatches/20150116.maniphestapplicationemails.php new file mode 100644 index 0000000000..c3e1f53eee --- /dev/null +++ b/resources/sql/autopatches/20150116.maniphestapplicationemails.php @@ -0,0 +1,20 @@ +setAddress($value) + ->setApplicationPHID($maniphest->getPHID()) + ->save(); + } catch (AphrontDuplicateKeyQueryException $ex) { + // already migrated? + } +} + +echo "Done.\n"; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2c67ae32aa..55a1870bd7 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1258,6 +1258,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', + 'PhabricatorApplicationEditEmailController' => 'applications/meta/controller/PhabricatorApplicationEditEmailController.php', 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php', 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', @@ -1946,6 +1947,9 @@ phutil_register_library_map(array( 'PhabricatorMetaMTAActor' => 'applications/metamta/query/PhabricatorMetaMTAActor.php', 'PhabricatorMetaMTAActorQuery' => 'applications/metamta/query/PhabricatorMetaMTAActorQuery.php', 'PhabricatorMetaMTAApplication' => 'applications/metamta/application/PhabricatorMetaMTAApplication.php', + 'PhabricatorMetaMTAApplicationEmail' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php', + 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php', + 'PhabricatorMetaMTAApplicationEmailQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', @@ -4430,6 +4434,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', + 'PhabricatorApplicationEditEmailController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationLaunchView' => 'AphrontTagView', 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', @@ -5155,6 +5160,12 @@ phutil_register_library_map(array( 'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorMetaMTAActorQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAApplication' => 'PhabricatorApplication', + 'PhabricatorMetaMTAApplicationEmail' => array( + 'PhabricatorMetaMTADAO', + 'PhabricatorPolicyInterface', + ), + 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorMetaMTAApplicationEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 83986cc5b2..d2231e4536 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -4,6 +4,7 @@ * @task info Application Information * @task ui UI Integration * @task uri URI Routing + * @task mail Email integration * @task fact Fact Integration * @task meta Application Management */ @@ -193,6 +194,22 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } +/* -( Email Integration )-------------------------------------------------- */ + + + public function supportsEmailIntegration() { + return false; + } + + protected function getInboundEmailSupportLink() { + return PhabricatorEnv::getDocLink('Configuring Inbound Email'); + } + + public function getAppEmailBlurb() { + throw new Exception('Not Implemented.'); + } + + /* -( Fact Integration )--------------------------------------------------- */ diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php index 00bbc83c60..0249bb6200 100644 --- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php +++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php @@ -109,6 +109,20 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication { return $items; } + public function supportsEmailIntegration() { + return true; + } + + public function getAppEmailBlurb() { + return pht( + 'Send email to these addresses to create tasks. %s', + phutil_tag( + 'a', + array( + 'href' => $this->getInboundEmailSupportLink(),), + pht('Learn More'))); + } + protected function getCustomCapabilities() { return array( ManiphestDefaultViewCapability::CAPABILITY => array( diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php index dbeb8bd402..337ebd8e43 100644 --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -294,9 +294,16 @@ EOTEXT 'metamta.maniphest.public-create-email', 'string', null) - ->setSummary(pht('Allow filing bugs via email.')) + ->setLocked(true) + ->setLockedMessage(pht( + 'This configuration is deprecated. See description for details.')) + ->setSummary(pht('DEPRECATED - Allow filing bugs via email.')) ->setDescription( pht( + 'This config has been deprecated in favor of [[ '. + '/applications/view/PhabricatorManiphestApplication/ | '. + 'application settings ]], which allow for multiple email '. + 'addresses and other functionality.'."\n\n". 'You can configure an email address like '. '"bugs@phabricator.example.com" which will automatically create '. 'Maniphest tasks when users send email to it. This relies on the '. diff --git a/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php b/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php index 2fb98fd91a..3f7c132cb9 100644 --- a/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php +++ b/src/applications/maniphest/mail/ManiphestCreateMailReceiver.php @@ -8,12 +8,18 @@ final class ManiphestCreateMailReceiver extends PhabricatorMailReceiver { } public function canAcceptMail(PhabricatorMetaMTAReceivedMail $mail) { - $config_key = 'metamta.maniphest.public-create-email'; - $create_address = PhabricatorEnv::getEnvConfig($config_key); + $maniphest_app = new PhabricatorManiphestApplication(); + $application_emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($this->getViewer()) + ->withApplicationPHIDs(array($maniphest_app->getPHID())) + ->execute(); foreach ($mail->getToAddresses() as $to_address) { - if ($this->matchAddresses($create_address, $to_address)) { - return true; + foreach ($application_emails as $application_email) { + $create_address = $application_email->getAddress(); + if ($this->matchAddresses($create_address, $to_address)) { + return true; + } } } diff --git a/src/applications/meta/application/PhabricatorApplicationsApplication.php b/src/applications/meta/application/PhabricatorApplicationsApplication.php index 4d18fd3628..dde0838df8 100644 --- a/src/applications/meta/application/PhabricatorApplicationsApplication.php +++ b/src/applications/meta/application/PhabricatorApplicationsApplication.php @@ -41,6 +41,8 @@ final class PhabricatorApplicationsApplication extends PhabricatorApplication { => 'PhabricatorApplicationDetailViewController', 'edit/(?P\w+)/' => 'PhabricatorApplicationEditController', + 'editemail/(?P\w+)/' + => 'PhabricatorApplicationEditEmailController', '(?P\w+)/(?Pinstall|uninstall)/' => 'PhabricatorApplicationUninstallController', ), diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index 264071b615..a2c8a6c9d0 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -3,23 +3,18 @@ final class PhabricatorApplicationDetailViewController extends PhabricatorApplicationsController { - private $application; public function shouldAllowPublic() { return true; } - public function willProcessRequest(array $data) { - $this->application = $data['application']; - } - - public function processRequest() { - $request = $this->getRequest(); + public function handleRequest(AphrontRequest $request) { $user = $request->getUser(); + $application = $request->getURIData('application'); $selected = id(new PhabricatorApplicationQuery()) ->setViewer($user) - ->withClasses(array($this->application)) + ->withClasses(array($application)) ->executeOne(); if (!$selected) { return new Aphront404Response(); @@ -119,6 +114,26 @@ final class PhabricatorApplicationDetailViewController idx($descriptions, $capability)); } + if ($application->supportsEmailIntegration()) { + $properties->addSectionHeader(pht('Application Emails')); + $properties->addTextContent($application->getAppEmailBlurb()); + $email_addresses = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($viewer) + ->withApplicationPHIDs(array($application->getPHID())) + ->execute(); + if (empty($email_addresses)) { + $properties->addProperty( + null, + pht('No email addresses configured.')); + } else { + foreach ($email_addresses as $email_address) { + $properties->addProperty( + null, + $email_address->getAddress()); + } + } + } + return $properties; } @@ -153,6 +168,18 @@ final class PhabricatorApplicationDetailViewController ->setWorkflow(!$can_edit) ->setHref($edit_uri)); + if ($selected->supportsEmailIntegration()) { + $edit_email_uri = $this->getApplicationURI( + 'editemail/'.get_class($selected).'/'); + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Application Emails')) + ->setIcon('fa-envelope') + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit) + ->setHref($edit_email_uri)); + } + if ($selected->canUninstall()) { if ($selected->isInstalled()) { $view->addAction( diff --git a/src/applications/meta/controller/PhabricatorApplicationEditEmailController.php b/src/applications/meta/controller/PhabricatorApplicationEditEmailController.php new file mode 100644 index 0000000000..052da430c1 --- /dev/null +++ b/src/applications/meta/controller/PhabricatorApplicationEditEmailController.php @@ -0,0 +1,307 @@ +getUser(); + $application = $request->getURIData('application'); + + $application = id(new PhabricatorApplicationQuery()) + ->setViewer($viewer) + ->withClasses(array($application)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$application) { + return new Aphront404Response(); + } + + $title = $application->getName(); + + $uri = $request->getRequestURI(); + $uri->setQueryParams(array()); + + $new = $request->getStr('new'); + $edit = $request->getInt('edit'); + $delete = $request->getInt('delete'); + + if ($new) { + return $this->returnNewAddressResponse($request, $uri, $application); + } + + if ($edit) { + return $this->returnEditAddressResponse($request, $uri, $edit); + } + + if ($delete) { + return $this->returnDeleteAddressResponse($request, $uri, $delete); + } + + $emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($viewer) + ->withApplicationPHIDs(array($application->getPHID())) + ->execute(); + + $highlight = $request->getInt('highlight'); + $rowc = array(); + $rows = array(); + foreach ($emails as $email) { + + $button_edit = javelin_tag( + 'a', + array( + 'class' => 'button small grey', + 'href' => $uri->alter('edit', $email->getID()), + 'sigil' => 'workflow', + ), + pht('Edit')); + + $button_remove = javelin_tag( + 'a', + array( + 'class' => 'button small grey', + 'href' => $uri->alter('delete', $email->getID()), + 'sigil' => 'workflow', + ), + pht('Delete')); + + if ($highlight == $email->getID()) { + $rowc[] = 'highlighted'; + } else { + $rowc[] = null; + } + + $rows[] = array( + $email->getAddress(), + $button_edit, + $button_remove, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setNoDataString(pht('No application emails created yet.')); + $table->setHeaders( + array( + pht('Email'), + pht('Edit'), + pht('Delete'), + )); + $table->setColumnClasses( + array( + 'wide', + 'action', + 'action', + )); + $table->setRowClasses($rowc); + $table->setColumnVisibility( + array( + true, + true, + true, + )); + $form = id(new AphrontFormView()) + ->setUser($viewer); + + $view_uri = $this->getApplicationURI('view/'.get_class($application).'/'); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($application->getName(), $view_uri); + $crumbs->addTextCrumb(pht('Edit Application Emails')); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Edit Application Emails: %s', $application->getName())); + + $icon = id(new PHUIIconView()) + ->setIconFont('fa-plus'); + $button = new PHUIButtonView(); + $button->setText(pht('Add New Address')); + $button->setTag('a'); + $button->setHref($uri->alter('new', 'true')); + $button->setIcon($icon); + $button->addSigil('workflow'); + $header->addActionLink($button); + + $object_box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->appendChild($table) + ->appendChild( + id(new PHUIBoxView()) + ->appendChild($application->getAppEmailBlurb()) + ->addPadding(PHUI::PADDING_MEDIUM)); + + return $this->buildApplicationPage( + array( + $crumbs, + $object_box, + ), + array( + 'title' => $title, + )); + } + + private function validateApplicationEmail($email) { + $errors = array(); + $e_email = true; + + if (!strlen($email)) { + $e_email = pht('Required'); + $errors[] = pht('Email is required.'); + } else if (!PhabricatorUserEmail::isValidAddress($email)) { + $e_email = pht('Invalid'); + $errors[] = PhabricatorUserEmail::describeValidAddresses(); + } else if (!PhabricatorUserEmail::isAllowedAddress($email)) { + $e_email = pht('Disallowed'); + $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); + } + $user_emails = id(new PhabricatorUserEmail()) + ->loadAllWhere('address = %s', $email); + if ($user_emails) { + $e_email = pht('Duplicate'); + $errors[] = pht('A user already has this email.'); + } + + return array($e_email, $errors); + } + + private function returnNewAddressResponse( + AphrontRequest $request, + PhutilURI $uri, + PhabricatorApplication $application) { + + $viewer = $request->getUser(); + $email_object = + PhabricatorMetaMTAApplicationEmail::initializeNewAppEmail($viewer) + ->setApplicationPHID($application->getPHID()); + + return $this->returnSaveAddressResponse( + $request, + $uri, + $email_object, + $is_new = true); + } + + private function returnEditAddressResponse( + AphrontRequest $request, + PhutilURI $uri, + $email_object_id) { + + $viewer = $request->getUser(); + $email_object = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($viewer) + ->withIDs(array($email_object_id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$email_object) { + return new Aphront404Response(); + } + + return $this->returnSaveAddressResponse( + $request, + $uri, + $email_object, + $is_new = false); + } + + private function returnSaveAddressResponse( + AphrontRequest $request, + PhutilURI $uri, + PhabricatorMetaMTAApplicationEmail $email_object, + $is_new) { + + $viewer = $request->getUser(); + + $e_email = true; + $email = null; + $errors = array(); + if ($request->isDialogFormPost()) { + $email = trim($request->getStr('email')); + list($e_email, $errors) = $this->validateApplicationEmail($email); + $email_object->setAddress($email); + + if (!$errors) { + try { + $email_object->save(); + return id(new AphrontRedirectResponse())->setURI( + $uri->alter('highlight', $email_object->getID())); + } catch (AphrontDuplicateKeyQueryException $ex) { + $e_email = pht('Duplicate'); + $errors[] = pht( + 'Another application is already configured to use this email '. + 'address.'); + } + } + } + + if ($errors) { + $errors = id(new AphrontErrorView()) + ->setErrors($errors); + } + + $form = id(new PHUIFormLayoutView()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Email')) + ->setName('email') + ->setValue($email_object->getAddress()) + ->setCaption(PhabricatorUserEmail::describeAllowedAddresses()) + ->setError($e_email)); + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle(pht('New Address')) + ->appendChild($errors) + ->appendChild($form) + ->addSubmitButton(pht('Save')) + ->addCancelButton($uri); + + if ($is_new) { + $dialog->addHiddenInput('new', 'true'); + } + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + private function returnDeleteAddressResponse( + AphrontRequest $request, + PhutilURI $uri, + $email_object_id) { + + $viewer = $request->getUser(); + $email_object = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($viewer) + ->withIDs(array($email_object_id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$email_object) { + return new Aphront404Response(); + } + + if ($request->isDialogFormPost()) { + $email_object->delete(); + return id(new AphrontRedirectResponse())->setURI($uri); + } + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->addHiddenInput('delete', $email_object_id) + ->setTitle(pht('Delete Address')) + ->appendParagraph(pht( + 'Are you sure you want to delete this email address?')) + ->addSubmitButton(pht('Delete')) + ->addCancelButton($uri); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} diff --git a/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php new file mode 100644 index 0000000000..367e267dc1 --- /dev/null +++ b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php @@ -0,0 +1,116 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withAddresses(array $addresses) { + $this->addresses = $addresses; + return $this; + } + + public function withApplicationPHIDs(array $phids) { + $this->applicationPHIDs = $phids; + return $this; + } + + protected function loadPage() { + $table = new PhabricatorMetaMTAApplicationEmail(); + $conn_r = $table->establishConnection('r'); + + $data = queryfx_all( + $conn_r, + 'SELECT * FROM %T appemail %Q %Q %Q %Q', + $table->getTableName(), + $this->buildWhereClause($conn_r), + $this->buildApplicationSearchGroupClause($conn_r), + $this->buildOrderClause($conn_r), + $this->buildLimitClause($conn_r)); + + return $table->loadAllFromArray($data); + } + + protected function willFilterPage(array $app_emails) { + $app_emails_map = mgroup($app_emails, 'getApplicationPHID'); + $applications = id(new PhabricatorApplicationQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs(array_keys($app_emails_map)) + ->execute(); + $applications = mpull($applications, null, 'getPHID'); + + foreach ($app_emails_map as $app_phid => $app_emails_group) { + foreach ($app_emails_group as $app_email) { + $application = idx($applications, $app_phid); + if (!$application) { + unset($app_emails[$app_phid]); + continue; + } + $app_email->attachApplication($application); + } + } + return $app_emails; + } + + private function buildWhereClause($conn_r) { + $where = array(); + + if ($this->addresses !== null) { + $where[] = qsprintf( + $conn_r, + 'appemail.address IN (%Ls)', + $this->addresses); + } + + if ($this->applicationPHIDs !== null) { + $where[] = qsprintf( + $conn_r, + 'appemail.applicationPHID IN (%Ls)', + $this->applicationPHIDs); + } + + if ($this->phids !== null) { + $where[] = qsprintf( + $conn_r, + 'appemail.phid IN (%Ls)', + $this->phids); + } + + if ($this->ids !== null) { + $where[] = qsprintf( + $conn_r, + 'appemail.id IN (%Ld)', + $this->ids); + } + + $where[] = $this->buildPagingClause($conn_r); + + return $this->formatWhereClause($where); + } + + protected function getPagingColumn() { + return 'appemail.id'; + } + + protected function getApplicationSearchObjectPHIDColumn() { + return 'appemail.phid'; + } + + public function getQueryApplicationClass() { + return 'PhabricatorMetaMTAApplication'; + } + +} diff --git a/src/applications/metamta/receiver/PhabricatorMailReceiver.php b/src/applications/metamta/receiver/PhabricatorMailReceiver.php index 1fd6068468..2a17034fd7 100644 --- a/src/applications/metamta/receiver/PhabricatorMailReceiver.php +++ b/src/applications/metamta/receiver/PhabricatorMailReceiver.php @@ -15,6 +15,10 @@ abstract class PhabricatorMailReceiver { $this->processReceivedMail($mail, $sender); } + public function getViewer() { + return PhabricatorUser::getOmnipotentUser(); + } + public function validateSender( PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { @@ -103,7 +107,7 @@ abstract class PhabricatorMailReceiver { if ($allow_email_users) { $from_obj = new PhutilEmailAddress($from); $xuser = id(new PhabricatorExternalAccountQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->setViewer($this->getViewer()) ->withAccountTypes(array('email')) ->withAccountDomains(array($from_obj->getDomainName(), 'self')) ->withAccountIDs(array($from_obj->getAddress())) diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php new file mode 100644 index 0000000000..c001b4b70c --- /dev/null +++ b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php @@ -0,0 +1,80 @@ + true, + self::CONFIG_SERIALIZATION => array( + 'configData' => self::SERIALIZATION_JSON, + ), + self::CONFIG_COLUMN_SCHEMA => array( + 'address' => 'sort128', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_address' => array( + 'columns' => array('address'), + 'unique' => true, + ), + 'key_application' => array( + 'columns' => array('applicationPHID'), + ), + ), + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + PhabricatorMetaMTAApplicationEmailPHIDType::TYPECONST); + } + + public static function initializeNewAppEmail(PhabricatorUser $actor) { + return id(new PhabricatorMetaMTAApplicationEmail()) + ->setConfigData(array()); + } + + public function attachApplication(PhabricatorApplication $app) { + $this->application = $app; + return $this; + } + + public function getApplication() { + return self::assertAttached($this->application); + } + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } + + public function getPolicy($capability) { + return $this->getApplication()->getPolicy($capability); + } + + public function hasAutomaticCapability( + $capability, + PhabricatorUser $viewer) { + + return $this->getApplication()->hasAutomaticCapability( + $capability, + $viewer); + } + + public function describeAutomaticCapability($capability) { + return $this->getApplication()->describeAutomaticCapability($capability); + } + +} diff --git a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php index 8f3e72a342..fbabe412c3 100644 --- a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php +++ b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php @@ -64,10 +64,9 @@ final class PhabricatorMetaMTAReceivedMailTestCase extends PhabricatorTestCase { } public function testDropUnknownSenderMail() { + $this->setManiphestCreateEmail(); + $env = PhabricatorEnv::beginScopedEnv(); - $env->overrideEnvConfig( - 'metamta.maniphest.public-create-email', - 'bugs@example.com'); $env->overrideEnvConfig('phabricator.allow-email-users', false); $env->overrideEnvConfig('metamta.maniphest.default-public-author', null); @@ -89,10 +88,7 @@ final class PhabricatorMetaMTAReceivedMailTestCase extends PhabricatorTestCase { public function testDropDisabledSenderMail() { - $env = PhabricatorEnv::beginScopedEnv(); - $env->overrideEnvConfig( - 'metamta.maniphest.public-create-email', - 'bugs@example.com'); + $this->setManiphestCreateEmail(); $user = $this->generateNewTestUser() ->setIsDisabled(true) @@ -114,4 +110,15 @@ final class PhabricatorMetaMTAReceivedMailTestCase extends PhabricatorTestCase { $mail->getStatus()); } + private function setManiphestCreateEmail() { + $maniphest_app = new PhabricatorManiphestApplication(); + try { + id(new PhabricatorMetaMTAApplicationEmail()) + ->setApplicationPHID($maniphest_app->getPHID()) + ->setAddress('bugs@example.com') + ->setConfigData(array()) + ->save(); + } catch (AphrontDuplicateKeyQueryException $ex) {} + } + } diff --git a/src/applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php b/src/applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php new file mode 100644 index 0000000000..1069b35793 --- /dev/null +++ b/src/applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php @@ -0,0 +1,44 @@ +withPHIDs($phids); + } + + public function loadHandles( + PhabricatorHandleQuery $query, + array $handles, + array $objects) { + + foreach ($handles as $phid => $handle) { + $email = $objects[$phid]; + + $handle->setName($email->getAddress()); + $handle->setFullName($email->getAddress()); + } + } +}