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

Maniphest - prevent uneditable tasks from being able to be closed as duplicates

Summary:
Fixes T7923.

Prevent the user from finding tasks that they can't edit in merge workflows. Also ensure that we query properly on final merge action just in case.

Test Plan: Tried to find a task I couldn't edit in various searches under the "merge" dialogue and couldn't find the task. Removed this big of code and tried to merge in a task and after hitting "merge" observed the page reloaded with no task merged in.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7923

Differential Revision: https://secure.phabricator.com/D12872

+80 -50
+14
src/applications/phid/query/PhabricatorHandleQuery.php
··· 3 3 final class PhabricatorHandleQuery 4 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 5 6 + private $objectCapabilities; 6 7 private $phids = array(); 7 8 8 9 public function withPHIDs(array $phids) { ··· 10 11 return $this; 11 12 } 12 13 14 + public function requireObjectCapabilities(array $capabilities) { 15 + $this->objectCapabilities = $capabilities; 16 + return $this; 17 + } 18 + 19 + protected function getRequiredObjectCapabilities() { 20 + if ($this->objectCapabilities) { 21 + return $this->objectCapabilities; 22 + } 23 + return $this->getRequiredCapabilities(); 24 + } 25 + 13 26 protected function loadPage() { 14 27 $types = PhabricatorPHIDType::getAllTypes(); 15 28 ··· 20 33 21 34 $object_query = id(new PhabricatorObjectQuery()) 22 35 ->withPHIDs($phids) 36 + ->requireCapabilities($this->getRequiredObjectCapabilities()) 23 37 ->setViewer($this->getViewer()); 24 38 25 39 $objects = $object_query->execute();
+1 -1
src/applications/search/application/PhabricatorSearchApplication.php
··· 32 32 '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSearchController', 33 33 'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?' 34 34 => 'PhabricatorSearchAttachController', 35 - 'select/(?P<type>\w+)/' 35 + 'select/(?P<type>\w+)/(?:(?P<action>\w+)/)?' 36 36 => 'PhabricatorSearchSelectController', 37 37 'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController', 38 38 'hovercard/(?P<mode>retrieve|test)/'
+24 -35
src/applications/search/controller/PhabricatorSearchAttachController.php
··· 3 3 final class PhabricatorSearchAttachController 4 4 extends PhabricatorSearchBaseController { 5 5 6 - private $phid; 7 - private $type; 8 - private $action; 9 - 10 - const ACTION_ATTACH = 'attach'; 11 - const ACTION_MERGE = 'merge'; 12 - const ACTION_DEPENDENCIES = 'dependencies'; 13 - const ACTION_BLOCKS = 'blocks'; 14 - const ACTION_EDGE = 'edge'; 15 - 16 - public function willProcessRequest(array $data) { 17 - $this->phid = $data['phid']; 18 - $this->type = $data['type']; 19 - $this->action = idx($data, 'action', self::ACTION_ATTACH); 20 - } 21 - 22 - public function processRequest() { 23 - 24 - $request = $this->getRequest(); 25 - $user = $request->getUser(); 6 + public function handleRequest(AphrontRequest $request) { 7 + $user = $request->getUser(); 8 + $phid = $request->getURIData('phid'); 9 + $attach_type = $request->getURIData('type'); 10 + $action = $request->getURIData('action', self::ACTION_ATTACH); 26 11 27 12 $handle = id(new PhabricatorHandleQuery()) 28 13 ->setViewer($user) 29 - ->withPHIDs(array($this->phid)) 14 + ->withPHIDs(array($phid)) 30 15 ->executeOne(); 31 16 32 17 $object_type = $handle->getType(); 33 - $attach_type = $this->type; 34 18 35 19 $object = id(new PhabricatorObjectQuery()) 36 20 ->setViewer($user) 37 - ->withPHIDs(array($this->phid)) 21 + ->withPHIDs(array($phid)) 38 22 ->executeOne(); 39 23 40 24 if (!$object) { ··· 42 26 } 43 27 44 28 $edge_type = null; 45 - switch ($this->action) { 29 + switch ($action) { 46 30 case self::ACTION_EDGE: 47 31 case self::ACTION_DEPENDENCIES: 48 32 case self::ACTION_BLOCKS: ··· 66 50 } 67 51 68 52 $old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 69 - $this->phid, 53 + $phid, 70 54 $edge_type); 71 55 $add_phids = $phids; 72 56 $rem_phids = array_diff($old_phids, $add_phids); ··· 100 84 } else { 101 85 if ($edge_type) { 102 86 $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( 103 - $this->phid, 87 + $phid, 104 88 $edge_type); 105 89 } else { 106 90 // This is a merge. ··· 108 92 } 109 93 } 110 94 111 - $strings = $this->getStrings(); 95 + $strings = $this->getStrings($attach_type, $action); 112 96 113 97 $handles = $this->loadViewerHandles($phids); 114 98 ··· 116 100 $obj_dialog 117 101 ->setUser($user) 118 102 ->setHandles($handles) 119 - ->setFilters($this->getFilters($strings)) 103 + ->setFilters($this->getFilters($strings, $attach_type)) 120 104 ->setSelectedFilter($strings['selected']) 121 - ->setExcluded($this->phid) 105 + ->setExcluded($phid) 122 106 ->setCancelURI($handle->getURI()) 123 - ->setSearchURI('/search/select/'.$attach_type.'/') 107 + ->setSearchURI('/search/select/'.$attach_type.'/'.$action.'/') 124 108 ->setTitle($strings['title']) 125 109 ->setHeader($strings['header']) 126 110 ->setButtonText($strings['button']) ··· 148 132 149 133 $targets = id(new ManiphestTaskQuery()) 150 134 ->setViewer($user) 135 + ->requireCapabilities( 136 + array( 137 + PhabricatorPolicyCapability::CAN_VIEW, 138 + PhabricatorPolicyCapability::CAN_EDIT, 139 + )) 151 140 ->withPHIDs(array_keys($phids)) 152 141 ->needSubscriberPHIDs(true) 153 142 ->needProjectPHIDs(true) ··· 208 197 return $response; 209 198 } 210 199 211 - private function getStrings() { 212 - switch ($this->type) { 200 + private function getStrings($attach_type, $action) { 201 + switch ($attach_type) { 213 202 case DifferentialRevisionPHIDType::TYPECONST: 214 203 $noun = 'Revisions'; 215 204 $selected = 'created'; ··· 228 217 break; 229 218 } 230 219 231 - switch ($this->action) { 220 + switch ($action) { 232 221 case self::ACTION_EDGE: 233 222 case self::ACTION_ATTACH: 234 223 $dialog_title = "Manage Attached {$noun}"; ··· 268 257 ); 269 258 } 270 259 271 - private function getFilters(array $strings) { 272 - if ($this->type == PholioMockPHIDType::TYPECONST) { 260 + private function getFilters(array $strings, $attach_type) { 261 + if ($attach_type == PholioMockPHIDType::TYPECONST) { 273 262 $filters = array( 274 263 'created' => 'Created By Me', 275 264 'all' => 'All '.$strings['target_plural_noun'],
+6
src/applications/search/controller/PhabricatorSearchBaseController.php
··· 2 2 3 3 abstract class PhabricatorSearchBaseController extends PhabricatorController { 4 4 5 + const ACTION_ATTACH = 'attach'; 6 + const ACTION_MERGE = 'merge'; 7 + const ACTION_DEPENDENCIES = 'dependencies'; 8 + const ACTION_BLOCKS = 'blocks'; 9 + const ACTION_EDGE = 'edge'; 10 + 5 11 public function buildStandardPageResponse($view, array $data) { 6 12 $page = $this->buildStandardPageView(); 7 13
+21 -14
src/applications/search/controller/PhabricatorSearchSelectController.php
··· 3 3 final class PhabricatorSearchSelectController 4 4 extends PhabricatorSearchBaseController { 5 5 6 - private $type; 7 - 8 - public function willProcessRequest(array $data) { 9 - $this->type = $data['type']; 10 - } 11 - 12 - public function processRequest() { 13 - $request = $this->getRequest(); 6 + public function handleRequest(AphrontRequest $request) { 14 7 $user = $request->getUser(); 8 + $type = $request->getURIData('type'); 9 + $action = $request->getURIData('action'); 15 10 16 11 $query = new PhabricatorSavedQuery(); 17 12 $query_str = $request->getStr('query'); 18 13 19 14 $query->setEngineClassName('PhabricatorSearchApplicationSearchEngine'); 20 15 $query->setParameter('query', $query_str); 21 - $query->setParameter('types', array($this->type)); 16 + $query->setParameter('types', array($type)); 22 17 23 18 $status_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; 24 19 ··· 31 26 $query->setParameter('authorPHIDs', array($user->getPHID())); 32 27 // TODO - if / when we allow pholio mocks to be archived, etc 33 28 // update this 34 - if ($this->type != PholioMockPHIDType::TYPECONST) { 29 + if ($type != PholioMockPHIDType::TYPECONST) { 35 30 $query->setParameter('statuses', array($status_open)); 36 31 } 37 32 break; ··· 42 37 43 38 $query->setParameter('excludePHIDs', array($request->getStr('exclude'))); 44 39 40 + $capabilities = array(PhabricatorPolicyCapability::CAN_VIEW); 41 + switch ($action) { 42 + case self::ACTION_MERGE: 43 + $capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; 44 + break; 45 + default: 46 + break; 47 + } 48 + 45 49 $results = id(new PhabricatorSearchDocumentQuery()) 46 50 ->setViewer($user) 51 + ->requireObjectCapabilities($capabilities) 47 52 ->withSavedQuery($query) 48 53 ->setOffset(0) 49 54 ->setLimit(100) 50 55 ->execute(); 51 56 52 57 $phids = array_fill_keys(mpull($results, 'getPHID'), true); 53 - $phids += $this->queryObjectNames($query_str); 58 + $phids += $this->queryObjectNames($query_str, $capabilities); 54 59 55 60 $phids = array_keys($phids); 56 61 $handles = $this->loadViewerHandles($phids); ··· 64 69 return id(new AphrontAjaxResponse())->setContent($data); 65 70 } 66 71 67 - private function queryObjectNames($query) { 68 - $viewer = $this->getRequest()->getUser(); 72 + private function queryObjectNames($query, $capabilities) { 73 + $request = $this->getRequest(); 74 + $viewer = $request->getUser(); 69 75 70 76 $objects = id(new PhabricatorObjectQuery()) 71 77 ->setViewer($viewer) 72 - ->withTypes(array($this->type)) 78 + ->requireCapabilities($capabilities) 79 + ->withTypes(array($request->getURIData('type'))) 73 80 ->withNames(array($query)) 74 81 ->execute(); 75 82
+14
src/applications/search/query/PhabricatorSearchDocumentQuery.php
··· 4 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 5 6 6 private $savedQuery; 7 + private $objectCapabilities; 7 8 8 9 public function withSavedQuery(PhabricatorSavedQuery $query) { 9 10 $this->savedQuery = $query; 10 11 return $this; 11 12 } 12 13 14 + public function requireObjectCapabilities(array $capabilities) { 15 + $this->objectCapabilities = $capabilities; 16 + return $this; 17 + } 18 + 19 + protected function getRequiredObjectCapabilities() { 20 + if ($this->objectCapabilities) { 21 + return $this->objectCapabilities; 22 + } 23 + return $this->getRequiredCapabilities(); 24 + } 25 + 13 26 protected function loadPage() { 14 27 $phids = $this->loadDocumentPHIDsWithoutPolicyChecks(); 15 28 16 29 $handles = id(new PhabricatorHandleQuery()) 17 30 ->setViewer($this->getViewer()) 31 + ->requireObjectCapabilities($this->getRequiredObjectCapabilities()) 18 32 ->withPHIDs($phids) 19 33 ->execute(); 20 34