1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-26 13:39:08 +01:00

MetaMTA - add (basic) application emails and deploy to Maniphest

Summary: Ref T5952, T3404. This lays the basic plumbing for how this will work, all the way to deploying on Maniphest. Aside from what is mentioned on T5952, I think page(s) on editing application emails could use a little more helpful text about what's going on, similar to how the config page that's getting deprecated works.

Test Plan: ran migration and noted my create email address migrated successfully. used bin/mail to make a task. added another email and used bin/mail to make a task. deleted an email. edited an email. invoked various error states and they all looked good.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T3404, T5952

Differential Revision: https://secure.phabricator.com/D11418
This commit is contained in:
Bob Trahan 2015-01-19 16:07:26 -08:00
parent a15852c112
commit 53b06408f4
15 changed files with 695 additions and 21 deletions

View file

@ -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};

View file

@ -0,0 +1,20 @@
<?php
$key = 'metamta.maniphest.public-create-email';
echo "Migrating `$key` to new application email infrastructure...\n";
$value = PhabricatorEnv::getEnvConfigIfExists($key);
$maniphest = new PhabricatorManiphestApplication();
if ($value) {
try {
PhabricatorMetaMTAApplicationEmail::initializeNewAppEmail(
PhabricatorUser::getOmnipotentUser())
->setAddress($value)
->setApplicationPHID($maniphest->getPHID())
->save();
} catch (AphrontDuplicateKeyQueryException $ex) {
// already migrated?
}
}
echo "Done.\n";

View file

@ -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',

View file

@ -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 )--------------------------------------------------- */

View file

@ -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(

View file

@ -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 '.

View file

@ -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;
}
}
}

View file

@ -41,6 +41,8 @@ final class PhabricatorApplicationsApplication extends PhabricatorApplication {
=> 'PhabricatorApplicationDetailViewController',
'edit/(?P<application>\w+)/'
=> 'PhabricatorApplicationEditController',
'editemail/(?P<application>\w+)/'
=> 'PhabricatorApplicationEditEmailController',
'(?P<application>\w+)/(?P<action>install|uninstall)/'
=> 'PhabricatorApplicationUninstallController',
),

View file

@ -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(

View file

@ -0,0 +1,307 @@
<?php
final class PhabricatorApplicationEditEmailController
extends PhabricatorApplicationsController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->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);
}
}

View file

@ -0,0 +1,116 @@
<?php
final class PhabricatorMetaMTAApplicationEmailQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $addresses;
private $applicationPHIDs;
public function withIDs(array $ids) {
$this->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';
}
}

View file

@ -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()))

View file

@ -0,0 +1,80 @@
<?php
final class PhabricatorMetaMTAApplicationEmail
extends PhabricatorMetaMTADAO
implements PhabricatorPolicyInterface {
protected $applicationPHID;
protected $address;
protected $configData;
private $application = self::ATTACHABLE;
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => 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);
}
}

View file

@ -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) {}
}
}

View file

@ -0,0 +1,44 @@
<?php
final class PhabricatorMetaMTAApplicationEmailPHIDType
extends PhabricatorPHIDType {
const TYPECONST = 'APPE';
public function getTypeName() {
return pht('Application Email');
}
public function getPHIDTypeApplicationClass() {
return 'PhabricatorMetaMTAApplication';
}
public function getTypeIcon() {
return 'fa-email bluegrey';
}
public function newObject() {
return new PhabricatorMetaMTAApplicationEmail();
}
protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids) {
return id(new PhabricatorMetaMTAApplicationEmailQuery())
->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());
}
}
}