1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Support Spaces in ApplicationEmail

Summary:
Ref T8498. Allow ApplicationEmail addresses to be put into spaces:

  - You can only see and send to addresses in Spaces you have access to.
  - Objects are created into the same space their address is associated with.

Test Plan:
  - Used `bin/mail receive-test` to send mail to various `xyz-bugs@...` addresses.
  - Saw objects created in the proper space.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T8498

Differential Revision: https://secure.phabricator.com/D13247
This commit is contained in:
epriestley 2015-06-11 10:23:56 -07:00
parent c71873ed7b
commit 0bc8382dfd
11 changed files with 183 additions and 130 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_metamta.metamta_applicationemail
ADD spacePHID VARBINARY(64);

View file

@ -5498,6 +5498,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorDestructibleInterface',
'PhabricatorSpacesInterface',
),
'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor',

View file

@ -58,6 +58,7 @@ final class ManiphestTask extends ManiphestDAO
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID())
->attachProjectPHIDs(array())
->attachSubscriberPHIDs(array());
}

View file

@ -16,24 +16,7 @@ final class PhabricatorMetaMTAApplicationEmailPanel
$viewer = $this->getViewer();
$application = $this->getApplication();
$addresses = id(new PhabricatorMetaMTAApplicationEmailQuery())
->setViewer($viewer)
->withApplicationPHIDs(array($application->getPHID()))
->execute();
$rows = array();
foreach ($addresses as $address) {
$rows[] = array(
$address->getAddress(),
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(pht('No email addresses configured.'))
->setHeaders(
array(
pht('Address'),
));
$table = $this->buildEmailTable($is_edit = false, null);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@ -91,68 +74,10 @@ final class PhabricatorMetaMTAApplicationEmailPanel
return $this->returnDeleteAddressResponse($request, $uri, $delete);
}
$emails = id(new PhabricatorMetaMTAApplicationEmailQuery())
->setViewer($viewer)
->withApplicationPHIDs(array($application->getPHID()))
->execute();
$table = $this->buildEmailTable(
$is_edit = true,
$request->getInt('id'));
$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);
@ -246,6 +171,8 @@ final class PhabricatorMetaMTAApplicationEmailPanel
$e_email = true;
$v_email = $email_object->getAddress();
$e_space = null;
$v_space = $email_object->getSpacePHID();
$v_default = $email_object->getConfigValue($config_default);
$validation_exception = null;
@ -253,11 +180,13 @@ final class PhabricatorMetaMTAApplicationEmailPanel
$e_email = null;
$v_email = trim($request->getStr('email'));
$v_space = $request->getStr('spacePHID');
$v_default = $request->getArr($config_default);
$v_default = nonempty(head($v_default), null);
$type_address =
PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS;
$type_space = PhabricatorTransactions::TYPE_SPACE;
$type_config =
PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG;
@ -269,6 +198,10 @@ final class PhabricatorMetaMTAApplicationEmailPanel
->setTransactionType($type_address)
->setNewValue($v_email);
$xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction())
->setTransactionType($type_space)
->setNewValue($v_space);
$xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction())
->setTransactionType($type_config)
->setMetadataValue($key_config, $config_default)
@ -287,6 +220,7 @@ final class PhabricatorMetaMTAApplicationEmailPanel
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_email = $ex->getShortMessage($type_address);
$e_space = $ex->getShortMessage($type_space);
}
}
@ -303,7 +237,22 @@ final class PhabricatorMetaMTAApplicationEmailPanel
->setLabel(pht('Email'))
->setName('email')
->setValue($v_email)
->setError($e_email))
->setError($e_email));
if (PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) {
$form->appendControl(
id(new AphrontFormSelectControl())
->setLabel(pht('Space'))
->setName('spacePHID')
->setValue($v_space)
->setError($e_space)
->setOptions(
PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer(
$viewer,
$v_space)));
}
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
@ -374,4 +323,85 @@ final class PhabricatorMetaMTAApplicationEmailPanel
return id(new AphrontDialogResponse())->setDialog($dialog);
}
private function buildEmailTable($is_edit, $highlight) {
$viewer = $this->getViewer();
$application = $this->getApplication();
$uri = new PhutilURI($this->getPanelURI());
$emails = id(new PhabricatorMetaMTAApplicationEmailQuery())
->setViewer($viewer)
->withApplicationPHIDs(array($application->getPHID()))
->execute();
$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;
}
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($email);
if ($space_phid) {
$email_space = $viewer->renderHandle($space_phid);
} else {
$email_space = null;
}
$rows[] = array(
$email_space,
$email->getAddress(),
$button_edit,
$button_remove,
);
}
$table = id(new AphrontTableView($rows))
->setNoDataString(pht('No application emails created yet.'));
$table->setHeaders(
array(
pht('Space'),
pht('Email'),
pht('Edit'),
pht('Delete'),
));
$table->setColumnClasses(
array(
'',
'wide',
'action',
'action',
));
$table->setRowClasses($rowc);
$table->setColumnVisibility(
array(
PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer),
true,
$is_edit,
$is_edit,
));
return $table;
}
}

View file

@ -35,19 +35,7 @@ final class PhabricatorMetaMTAApplicationEmailQuery
}
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);
return $this->loadStandardPage(new PhabricatorMetaMTAApplicationEmail());
}
protected function willFilterPage(array $app_emails) {
@ -71,47 +59,45 @@ final class PhabricatorMetaMTAApplicationEmailQuery
return $app_emails;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->addresses !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'appemail.address IN (%Ls)',
$this->addresses);
}
if ($this->addressPrefix !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'appemail.address LIKE %>',
$this->addressPrefix);
}
if ($this->applicationPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'appemail.applicationPHID IN (%Ls)',
$this->applicationPHIDs);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'appemail.phid IN (%Ls)',
$this->phids);
}
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
$conn,
'appemail.id IN (%Ld)',
$this->ids);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
return $where;
}
protected function getPrimaryTableAlias() {

View file

@ -5,11 +5,13 @@ final class PhabricatorMetaMTAApplicationEmail
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface,
PhabricatorDestructibleInterface {
PhabricatorDestructibleInterface,
PhabricatorSpacesInterface {
protected $applicationPHID;
protected $address;
protected $configData;
protected $spacePHID;
private $application = self::ATTACHABLE;
@ -43,6 +45,7 @@ final class PhabricatorMetaMTAApplicationEmail
public static function initializeNewAppEmail(PhabricatorUser $actor) {
return id(new PhabricatorMetaMTAApplicationEmail())
->setSpacePHID($actor->getDefaultSpacePHID())
->setConfigData(array());
}
@ -143,4 +146,12 @@ final class PhabricatorMetaMTAApplicationEmail
$this->delete();
}
/* -( PhabricatorSpacesInterface )----------------------------------------- */
public function getSpacePHID() {
return $this->spacePHID;
}
}

View file

@ -38,7 +38,8 @@ final class PhabricatorPaste extends PhabricatorPasteDAO
->setTitle('')
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy);
->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID());
}
public function getURI() {

View file

@ -48,7 +48,8 @@ final class PholioMock extends PholioDAO
->attachImages(array())
->setStatus(self::STATUS_OPEN)
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy);
->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID());
}
public function getMonogram() {

View file

@ -170,6 +170,31 @@ final class PhabricatorSpacesNamespaceQuery
return $spaces;
}
public static function getSpaceOptionsForViewer(
PhabricatorUser $viewer,
$space_phid) {
$viewer_spaces = self::getViewerSpaces($viewer);
$map = array();
foreach ($viewer_spaces as $space) {
// Skip archived spaces, unless the object is already in that space.
if ($space->getIsArchived()) {
if ($space->getPHID() != $space_phid) {
continue;
}
}
$map[$space->getPHID()] = pht(
'Space %s: %s',
$space->getMonogram(),
$space->getNamespaceName());
}
asort($map);
return $map;
}
/**

View file

@ -56,6 +56,22 @@ abstract class PhabricatorApplicationTransactionReplyHandler
final protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$viewer = $this->getActor();
$object = $this->getMailReceiver();
$app_email = $this->getApplicationEmail();
$is_new = !$object->getID();
// If this is a new object which implements the Spaces interface and was
// created by sending mail to an ApplicationEmail address, put the object
// in the same Space the address is in.
if ($is_new) {
if ($object instanceof PhabricatorSpacesInterface) {
if ($app_email) {
$space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID(
$app_email);
$object->setSpacePHID($space_phid);
}
}
}
$body_data = $mail->parseBody();
$body = $body_data['body'];

View file

@ -265,7 +265,9 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
$select = AphrontFormSelectControl::renderSelectTag(
$space_phid,
$this->getSpaceOptions($space_phid),
PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer(
$viewer,
$space_phid),
array(
'name' => 'spacePHID',
));
@ -273,27 +275,4 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
return $select;
}
protected function getSpaceOptions($space_phid) {
$viewer = $this->getUser();
$viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer);
$map = array();
foreach ($viewer_spaces as $space) {
// Skip archived spaces, unless the object is already in that space.
if ($space->getIsArchived()) {
if ($space->getPHID() != $space_phid) {
continue;
}
}
$map[$space->getPHID()] = pht(
'Space %s: %s',
$space->getMonogram(),
$space->getNamespaceName());
}
asort($map);
return $map;
}
}