@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+183 -130
+2
resources/sql/autopatches/20150611.spaces.2.appmail.sql
··· 1 + ALTER TABLE {$NAMESPACE}_metamta.metamta_applicationemail 2 + ADD spacePHID VARBINARY(64);
+1
src/__phutil_library_map__.php
··· 5498 5498 'PhabricatorPolicyInterface', 5499 5499 'PhabricatorApplicationTransactionInterface', 5500 5500 'PhabricatorDestructibleInterface', 5501 + 'PhabricatorSpacesInterface', 5501 5502 ), 5502 5503 'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource', 5503 5504 'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor',
+1
src/applications/maniphest/storage/ManiphestTask.php
··· 58 58 ->setAuthorPHID($actor->getPHID()) 59 59 ->setViewPolicy($view_policy) 60 60 ->setEditPolicy($edit_policy) 61 + ->setSpacePHID($actor->getDefaultSpacePHID()) 61 62 ->attachProjectPHIDs(array()) 62 63 ->attachSubscriberPHIDs(array()); 63 64 }
+110 -80
src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php
··· 16 16 $viewer = $this->getViewer(); 17 17 $application = $this->getApplication(); 18 18 19 - $addresses = id(new PhabricatorMetaMTAApplicationEmailQuery()) 20 - ->setViewer($viewer) 21 - ->withApplicationPHIDs(array($application->getPHID())) 22 - ->execute(); 23 - 24 - $rows = array(); 25 - foreach ($addresses as $address) { 26 - $rows[] = array( 27 - $address->getAddress(), 28 - ); 29 - } 30 - 31 - $table = id(new AphrontTableView($rows)) 32 - ->setNoDataString(pht('No email addresses configured.')) 33 - ->setHeaders( 34 - array( 35 - pht('Address'), 36 - )); 19 + $table = $this->buildEmailTable($is_edit = false, null); 37 20 38 21 $can_edit = PhabricatorPolicyFilter::hasCapability( 39 22 $viewer, ··· 91 74 return $this->returnDeleteAddressResponse($request, $uri, $delete); 92 75 } 93 76 94 - $emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) 95 - ->setViewer($viewer) 96 - ->withApplicationPHIDs(array($application->getPHID())) 97 - ->execute(); 77 + $table = $this->buildEmailTable( 78 + $is_edit = true, 79 + $request->getInt('id')); 98 80 99 - $highlight = $request->getInt('highlight'); 100 - $rowc = array(); 101 - $rows = array(); 102 - foreach ($emails as $email) { 103 - 104 - $button_edit = javelin_tag( 105 - 'a', 106 - array( 107 - 'class' => 'button small grey', 108 - 'href' => $uri->alter('edit', $email->getID()), 109 - 'sigil' => 'workflow', 110 - ), 111 - pht('Edit')); 112 - 113 - $button_remove = javelin_tag( 114 - 'a', 115 - array( 116 - 'class' => 'button small grey', 117 - 'href' => $uri->alter('delete', $email->getID()), 118 - 'sigil' => 'workflow', 119 - ), 120 - pht('Delete')); 121 - 122 - if ($highlight == $email->getID()) { 123 - $rowc[] = 'highlighted'; 124 - } else { 125 - $rowc[] = null; 126 - } 127 - 128 - $rows[] = array( 129 - $email->getAddress(), 130 - $button_edit, 131 - $button_remove, 132 - ); 133 - } 134 - 135 - $table = id(new AphrontTableView($rows)) 136 - ->setNoDataString(pht('No application emails created yet.')); 137 - $table->setHeaders( 138 - array( 139 - pht('Email'), 140 - pht('Edit'), 141 - pht('Delete'), 142 - )); 143 - $table->setColumnClasses( 144 - array( 145 - 'wide', 146 - 'action', 147 - 'action', 148 - )); 149 - $table->setRowClasses($rowc); 150 - $table->setColumnVisibility( 151 - array( 152 - true, 153 - true, 154 - true, 155 - )); 156 81 $form = id(new AphrontFormView()) 157 82 ->setUser($viewer); 158 83 ··· 246 171 247 172 $e_email = true; 248 173 $v_email = $email_object->getAddress(); 174 + $e_space = null; 175 + $v_space = $email_object->getSpacePHID(); 249 176 $v_default = $email_object->getConfigValue($config_default); 250 177 251 178 $validation_exception = null; ··· 253 180 $e_email = null; 254 181 255 182 $v_email = trim($request->getStr('email')); 183 + $v_space = $request->getStr('spacePHID'); 256 184 $v_default = $request->getArr($config_default); 257 185 $v_default = nonempty(head($v_default), null); 258 186 259 187 $type_address = 260 188 PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS; 189 + $type_space = PhabricatorTransactions::TYPE_SPACE; 261 190 $type_config = 262 191 PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG; 263 192 ··· 270 199 ->setNewValue($v_email); 271 200 272 201 $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) 202 + ->setTransactionType($type_space) 203 + ->setNewValue($v_space); 204 + 205 + $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) 273 206 ->setTransactionType($type_config) 274 207 ->setMetadataValue($key_config, $config_default) 275 208 ->setNewValue($v_default); ··· 287 220 } catch (PhabricatorApplicationTransactionValidationException $ex) { 288 221 $validation_exception = $ex; 289 222 $e_email = $ex->getShortMessage($type_address); 223 + $e_space = $ex->getShortMessage($type_space); 290 224 } 291 225 } 292 226 ··· 303 237 ->setLabel(pht('Email')) 304 238 ->setName('email') 305 239 ->setValue($v_email) 306 - ->setError($e_email)) 240 + ->setError($e_email)); 241 + 242 + if (PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) { 243 + $form->appendControl( 244 + id(new AphrontFormSelectControl()) 245 + ->setLabel(pht('Space')) 246 + ->setName('spacePHID') 247 + ->setValue($v_space) 248 + ->setError($e_space) 249 + ->setOptions( 250 + PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer( 251 + $viewer, 252 + $v_space))); 253 + } 254 + 255 + $form 307 256 ->appendControl( 308 257 id(new AphrontFormTokenizerControl()) 309 258 ->setDatasource(new PhabricatorPeopleDatasource()) ··· 372 321 ->addCancelButton($uri); 373 322 374 323 return id(new AphrontDialogResponse())->setDialog($dialog); 324 + } 325 + 326 + private function buildEmailTable($is_edit, $highlight) { 327 + $viewer = $this->getViewer(); 328 + $application = $this->getApplication(); 329 + $uri = new PhutilURI($this->getPanelURI()); 330 + 331 + $emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) 332 + ->setViewer($viewer) 333 + ->withApplicationPHIDs(array($application->getPHID())) 334 + ->execute(); 335 + 336 + $rowc = array(); 337 + $rows = array(); 338 + foreach ($emails as $email) { 339 + 340 + $button_edit = javelin_tag( 341 + 'a', 342 + array( 343 + 'class' => 'button small grey', 344 + 'href' => $uri->alter('edit', $email->getID()), 345 + 'sigil' => 'workflow', 346 + ), 347 + pht('Edit')); 348 + 349 + $button_remove = javelin_tag( 350 + 'a', 351 + array( 352 + 'class' => 'button small grey', 353 + 'href' => $uri->alter('delete', $email->getID()), 354 + 'sigil' => 'workflow', 355 + ), 356 + pht('Delete')); 357 + 358 + if ($highlight == $email->getID()) { 359 + $rowc[] = 'highlighted'; 360 + } else { 361 + $rowc[] = null; 362 + } 363 + 364 + $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($email); 365 + if ($space_phid) { 366 + $email_space = $viewer->renderHandle($space_phid); 367 + } else { 368 + $email_space = null; 369 + } 370 + 371 + $rows[] = array( 372 + $email_space, 373 + $email->getAddress(), 374 + $button_edit, 375 + $button_remove, 376 + ); 377 + } 378 + 379 + $table = id(new AphrontTableView($rows)) 380 + ->setNoDataString(pht('No application emails created yet.')); 381 + $table->setHeaders( 382 + array( 383 + pht('Space'), 384 + pht('Email'), 385 + pht('Edit'), 386 + pht('Delete'), 387 + )); 388 + $table->setColumnClasses( 389 + array( 390 + '', 391 + 'wide', 392 + 'action', 393 + 'action', 394 + )); 395 + $table->setRowClasses($rowc); 396 + $table->setColumnVisibility( 397 + array( 398 + PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer), 399 + true, 400 + $is_edit, 401 + $is_edit, 402 + )); 403 + 404 + return $table; 375 405 } 376 406 377 407 }
+9 -23
src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php
··· 35 35 } 36 36 37 37 protected function loadPage() { 38 - $table = new PhabricatorMetaMTAApplicationEmail(); 39 - $conn_r = $table->establishConnection('r'); 40 - 41 - $data = queryfx_all( 42 - $conn_r, 43 - 'SELECT * FROM %T appemail %Q %Q %Q %Q', 44 - $table->getTableName(), 45 - $this->buildWhereClause($conn_r), 46 - $this->buildApplicationSearchGroupClause($conn_r), 47 - $this->buildOrderClause($conn_r), 48 - $this->buildLimitClause($conn_r)); 49 - 50 - return $table->loadAllFromArray($data); 38 + return $this->loadStandardPage(new PhabricatorMetaMTAApplicationEmail()); 51 39 } 52 40 53 41 protected function willFilterPage(array $app_emails) { ··· 71 59 return $app_emails; 72 60 } 73 61 74 - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { 75 - $where = array(); 62 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 63 + $where = parent::buildWhereClauseParts($conn); 76 64 77 65 if ($this->addresses !== null) { 78 66 $where[] = qsprintf( 79 - $conn_r, 67 + $conn, 80 68 'appemail.address IN (%Ls)', 81 69 $this->addresses); 82 70 } 83 71 84 72 if ($this->addressPrefix !== null) { 85 73 $where[] = qsprintf( 86 - $conn_r, 74 + $conn, 87 75 'appemail.address LIKE %>', 88 76 $this->addressPrefix); 89 77 } 90 78 91 79 if ($this->applicationPHIDs !== null) { 92 80 $where[] = qsprintf( 93 - $conn_r, 81 + $conn, 94 82 'appemail.applicationPHID IN (%Ls)', 95 83 $this->applicationPHIDs); 96 84 } 97 85 98 86 if ($this->phids !== null) { 99 87 $where[] = qsprintf( 100 - $conn_r, 88 + $conn, 101 89 'appemail.phid IN (%Ls)', 102 90 $this->phids); 103 91 } 104 92 105 93 if ($this->ids !== null) { 106 94 $where[] = qsprintf( 107 - $conn_r, 95 + $conn, 108 96 'appemail.id IN (%Ld)', 109 97 $this->ids); 110 98 } 111 99 112 - $where[] = $this->buildPagingClause($conn_r); 113 - 114 - return $this->formatWhereClause($where); 100 + return $where; 115 101 } 116 102 117 103 protected function getPrimaryTableAlias() {
+12 -1
src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php
··· 5 5 implements 6 6 PhabricatorPolicyInterface, 7 7 PhabricatorApplicationTransactionInterface, 8 - PhabricatorDestructibleInterface { 8 + PhabricatorDestructibleInterface, 9 + PhabricatorSpacesInterface { 9 10 10 11 protected $applicationPHID; 11 12 protected $address; 12 13 protected $configData; 14 + protected $spacePHID; 13 15 14 16 private $application = self::ATTACHABLE; 15 17 ··· 43 45 44 46 public static function initializeNewAppEmail(PhabricatorUser $actor) { 45 47 return id(new PhabricatorMetaMTAApplicationEmail()) 48 + ->setSpacePHID($actor->getDefaultSpacePHID()) 46 49 ->setConfigData(array()); 47 50 } 48 51 ··· 141 144 public function destroyObjectPermanently( 142 145 PhabricatorDestructionEngine $engine) { 143 146 $this->delete(); 147 + } 148 + 149 + 150 + /* -( PhabricatorSpacesInterface )----------------------------------------- */ 151 + 152 + 153 + public function getSpacePHID() { 154 + return $this->spacePHID; 144 155 } 145 156 146 157 }
+2 -1
src/applications/paste/storage/PhabricatorPaste.php
··· 38 38 ->setTitle('') 39 39 ->setAuthorPHID($actor->getPHID()) 40 40 ->setViewPolicy($view_policy) 41 - ->setEditPolicy($edit_policy); 41 + ->setEditPolicy($edit_policy) 42 + ->setSpacePHID($actor->getDefaultSpacePHID()); 42 43 } 43 44 44 45 public function getURI() {
+2 -1
src/applications/pholio/storage/PholioMock.php
··· 48 48 ->attachImages(array()) 49 49 ->setStatus(self::STATUS_OPEN) 50 50 ->setViewPolicy($view_policy) 51 - ->setEditPolicy($edit_policy); 51 + ->setEditPolicy($edit_policy) 52 + ->setSpacePHID($actor->getDefaultSpacePHID()); 52 53 } 53 54 54 55 public function getMonogram() {
+25
src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php
··· 170 170 return $spaces; 171 171 } 172 172 173 + public static function getSpaceOptionsForViewer( 174 + PhabricatorUser $viewer, 175 + $space_phid) { 176 + 177 + $viewer_spaces = self::getViewerSpaces($viewer); 178 + 179 + $map = array(); 180 + foreach ($viewer_spaces as $space) { 181 + 182 + // Skip archived spaces, unless the object is already in that space. 183 + if ($space->getIsArchived()) { 184 + if ($space->getPHID() != $space_phid) { 185 + continue; 186 + } 187 + } 188 + 189 + $map[$space->getPHID()] = pht( 190 + 'Space %s: %s', 191 + $space->getMonogram(), 192 + $space->getNamespaceName()); 193 + } 194 + asort($map); 195 + 196 + return $map; 197 + } 173 198 174 199 175 200 /**
+16
src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php
··· 56 56 final protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { 57 57 $viewer = $this->getActor(); 58 58 $object = $this->getMailReceiver(); 59 + $app_email = $this->getApplicationEmail(); 60 + 61 + $is_new = !$object->getID(); 62 + 63 + // If this is a new object which implements the Spaces interface and was 64 + // created by sending mail to an ApplicationEmail address, put the object 65 + // in the same Space the address is in. 66 + if ($is_new) { 67 + if ($object instanceof PhabricatorSpacesInterface) { 68 + if ($app_email) { 69 + $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID( 70 + $app_email); 71 + $object->setSpacePHID($space_phid); 72 + } 73 + } 74 + } 59 75 60 76 $body_data = $mail->parseBody(); 61 77 $body = $body_data['body'];
+3 -24
src/view/form/control/AphrontFormPolicyControl.php
··· 265 265 266 266 $select = AphrontFormSelectControl::renderSelectTag( 267 267 $space_phid, 268 - $this->getSpaceOptions($space_phid), 268 + PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer( 269 + $viewer, 270 + $space_phid), 269 271 array( 270 272 'name' => 'spacePHID', 271 273 )); ··· 273 275 return $select; 274 276 } 275 277 276 - protected function getSpaceOptions($space_phid) { 277 - $viewer = $this->getUser(); 278 - $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); 279 - 280 - $map = array(); 281 - foreach ($viewer_spaces as $space) { 282 - 283 - // Skip archived spaces, unless the object is already in that space. 284 - if ($space->getIsArchived()) { 285 - if ($space->getPHID() != $space_phid) { 286 - continue; 287 - } 288 - } 289 - 290 - $map[$space->getPHID()] = pht( 291 - 'Space %s: %s', 292 - $space->getMonogram(), 293 - $space->getNamespaceName()); 294 - } 295 - asort($map); 296 - 297 - return $map; 298 - } 299 278 }