mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-27 07:50:57 +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:
parent
c71873ed7b
commit
0bc8382dfd
11 changed files with 183 additions and 130 deletions
2
resources/sql/autopatches/20150611.spaces.2.appmail.sql
Normal file
2
resources/sql/autopatches/20150611.spaces.2.appmail.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_metamta.metamta_applicationemail
|
||||
ADD spacePHID VARBINARY(64);
|
|
@ -5498,6 +5498,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
'PhabricatorSpacesInterface',
|
||||
),
|
||||
'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue