Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/phid/query/PhabricatorHandleQuery.php b/src/applications/phid/query/PhabricatorHandleQuery.php
index 296116312b..2635b84298 100644
--- a/src/applications/phid/query/PhabricatorHandleQuery.php
+++ b/src/applications/phid/query/PhabricatorHandleQuery.php
@@ -1,74 +1,88 @@
<?php
final class PhabricatorHandleQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
+ private $objectCapabilities;
private $phids = array();
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
+ public function requireObjectCapabilities(array $capabilities) {
+ $this->objectCapabilities = $capabilities;
+ return $this;
+ }
+
+ protected function getRequiredObjectCapabilities() {
+ if ($this->objectCapabilities) {
+ return $this->objectCapabilities;
+ }
+ return $this->getRequiredCapabilities();
+ }
+
protected function loadPage() {
$types = PhabricatorPHIDType::getAllTypes();
$phids = array_unique($this->phids);
if (!$phids) {
return array();
}
$object_query = id(new PhabricatorObjectQuery())
->withPHIDs($phids)
+ ->requireCapabilities($this->getRequiredObjectCapabilities())
->setViewer($this->getViewer());
$objects = $object_query->execute();
$filtered = $object_query->getPolicyFilteredPHIDs();
$groups = array();
foreach ($phids as $phid) {
$type = phid_get_type($phid);
$groups[$type][] = $phid;
}
$results = array();
foreach ($groups as $type => $phid_group) {
$handles = array();
foreach ($phid_group as $key => $phid) {
if (isset($handles[$phid])) {
unset($phid_group[$key]);
// The input had a duplicate PHID; just skip it.
continue;
}
$handles[$phid] = id(new PhabricatorObjectHandle())
->setType($type)
->setPHID($phid);
if (isset($objects[$phid])) {
$handles[$phid]->setComplete(true);
} else if (isset($filtered[$phid])) {
$handles[$phid]->setPolicyFiltered(true);
}
}
if (isset($types[$type])) {
$type_objects = array_select_keys($objects, $phid_group);
if ($type_objects) {
$have_object_phids = array_keys($type_objects);
$types[$type]->loadHandles(
$this,
array_select_keys($handles, $have_object_phids),
$type_objects);
}
}
$results += $handles;
}
return $results;
}
public function getQueryApplicationClass() {
return null;
}
}
diff --git a/src/applications/search/application/PhabricatorSearchApplication.php b/src/applications/search/application/PhabricatorSearchApplication.php
index 51d5e9780c..f350438616 100644
--- a/src/applications/search/application/PhabricatorSearchApplication.php
+++ b/src/applications/search/application/PhabricatorSearchApplication.php
@@ -1,48 +1,48 @@
<?php
final class PhabricatorSearchApplication extends PhabricatorApplication {
public function getBaseURI() {
return '/search/';
}
public function getName() {
return pht('Search');
}
public function getShortDescription() {
return pht('Full-Text Search');
}
public function getFlavorText() {
return pht('Find stuff in big piles.');
}
public function getFontIcon() {
return 'fa-search';
}
public function isLaunchable() {
return false;
}
public function getRoutes() {
return array(
'/search/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorSearchController',
'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchAttachController',
- 'select/(?P<type>\w+)/'
+ 'select/(?P<type>\w+)/(?:(?P<action>\w+)/)?'
=> 'PhabricatorSearchSelectController',
'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController',
'hovercard/(?P<mode>retrieve|test)/'
=> 'PhabricatorSearchHovercardController',
'edit/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
=> 'PhabricatorSearchDeleteController',
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
),
);
}
}
diff --git a/src/applications/search/controller/PhabricatorSearchAttachController.php b/src/applications/search/controller/PhabricatorSearchAttachController.php
index e08fd7734c..b2e0a92b9d 100644
--- a/src/applications/search/controller/PhabricatorSearchAttachController.php
+++ b/src/applications/search/controller/PhabricatorSearchAttachController.php
@@ -1,335 +1,324 @@
<?php
final class PhabricatorSearchAttachController
extends PhabricatorSearchBaseController {
- private $phid;
- private $type;
- private $action;
-
- const ACTION_ATTACH = 'attach';
- const ACTION_MERGE = 'merge';
- const ACTION_DEPENDENCIES = 'dependencies';
- const ACTION_BLOCKS = 'blocks';
- const ACTION_EDGE = 'edge';
-
- public function willProcessRequest(array $data) {
- $this->phid = $data['phid'];
- $this->type = $data['type'];
- $this->action = idx($data, 'action', self::ACTION_ATTACH);
- }
-
- public function processRequest() {
-
- $request = $this->getRequest();
- $user = $request->getUser();
+ public function handleRequest(AphrontRequest $request) {
+ $user = $request->getUser();
+ $phid = $request->getURIData('phid');
+ $attach_type = $request->getURIData('type');
+ $action = $request->getURIData('action', self::ACTION_ATTACH);
$handle = id(new PhabricatorHandleQuery())
->setViewer($user)
- ->withPHIDs(array($this->phid))
+ ->withPHIDs(array($phid))
->executeOne();
$object_type = $handle->getType();
- $attach_type = $this->type;
$object = id(new PhabricatorObjectQuery())
->setViewer($user)
- ->withPHIDs(array($this->phid))
+ ->withPHIDs(array($phid))
->executeOne();
if (!$object) {
return new Aphront404Response();
}
$edge_type = null;
- switch ($this->action) {
+ switch ($action) {
case self::ACTION_EDGE:
case self::ACTION_DEPENDENCIES:
case self::ACTION_BLOCKS:
case self::ACTION_ATTACH:
$edge_type = $this->getEdgeType($object_type, $attach_type);
break;
}
if ($request->isFormPost()) {
$phids = explode(';', $request->getStr('phids'));
$phids = array_filter($phids);
$phids = array_values($phids);
if ($edge_type) {
if (!$object instanceof PhabricatorApplicationTransactionInterface) {
throw new Exception(
pht(
'Expected object ("%s") to implement interface "%s".',
get_class($object),
'PhabricatorApplicationTransactionInterface'));
}
$old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
- $this->phid,
+ $phid,
$edge_type);
$add_phids = $phids;
$rem_phids = array_diff($old_phids, $add_phids);
$txn_editor = $object->getApplicationTransactionEditor()
->setActor($user)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true);
$txn_template = $object->getApplicationTransactionTemplate()
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $edge_type)
->setNewValue(array(
'+' => array_fuse($add_phids),
'-' => array_fuse($rem_phids),
));
try {
$txn_editor->applyTransactions(
$object->getApplicationTransactionObject(),
array($txn_template));
} catch (PhabricatorEdgeCycleException $ex) {
$this->raiseGraphCycleException($ex);
}
return id(new AphrontReloadResponse())->setURI($handle->getURI());
} else {
return $this->performMerge($object, $handle, $phids);
}
} else {
if ($edge_type) {
$phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
- $this->phid,
+ $phid,
$edge_type);
} else {
// This is a merge.
$phids = array();
}
}
- $strings = $this->getStrings();
+ $strings = $this->getStrings($attach_type, $action);
$handles = $this->loadViewerHandles($phids);
$obj_dialog = new PhabricatorObjectSelectorDialog();
$obj_dialog
->setUser($user)
->setHandles($handles)
- ->setFilters($this->getFilters($strings))
+ ->setFilters($this->getFilters($strings, $attach_type))
->setSelectedFilter($strings['selected'])
- ->setExcluded($this->phid)
+ ->setExcluded($phid)
->setCancelURI($handle->getURI())
- ->setSearchURI('/search/select/'.$attach_type.'/')
+ ->setSearchURI('/search/select/'.$attach_type.'/'.$action.'/')
->setTitle($strings['title'])
->setHeader($strings['header'])
->setButtonText($strings['button'])
->setInstructions($strings['instructions']);
$dialog = $obj_dialog->buildDialog();
return id(new AphrontDialogResponse())->setDialog($dialog);
}
private function performMerge(
ManiphestTask $task,
PhabricatorObjectHandle $handle,
array $phids) {
$user = $this->getRequest()->getUser();
$response = id(new AphrontReloadResponse())->setURI($handle->getURI());
$phids = array_fill_keys($phids, true);
unset($phids[$task->getPHID()]); // Prevent merging a task into itself.
if (!$phids) {
return $response;
}
$targets = id(new ManiphestTaskQuery())
->setViewer($user)
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
->withPHIDs(array_keys($phids))
->needSubscriberPHIDs(true)
->needProjectPHIDs(true)
->execute();
if (empty($targets)) {
return $response;
}
$editor = id(new ManiphestTransactionEditor())
->setActor($user)
->setContentSourceFromRequest($this->getRequest())
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$cc_vector = array();
// since we loaded this via a generic object query, go ahead and get the
// attach the subscriber and project phids now
$task->attachSubscriberPHIDs(
PhabricatorSubscribersQuery::loadSubscribersForPHID($task->getPHID()));
$task->attachProjectPHIDs(
PhabricatorEdgeQuery::loadDestinationPHIDs($task->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST));
$cc_vector[] = $task->getSubscriberPHIDs();
foreach ($targets as $target) {
$cc_vector[] = $target->getSubscriberPHIDs();
$cc_vector[] = array(
$target->getAuthorPHID(),
$target->getOwnerPHID(),
);
$merged_into_txn = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_MERGED_INTO)
->setNewValue($task->getPHID());
$editor->applyTransactions(
$target,
array($merged_into_txn));
}
$all_ccs = array_mergev($cc_vector);
$all_ccs = array_filter($all_ccs);
$all_ccs = array_unique($all_ccs);
$add_ccs = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue(array('=' => $all_ccs));
$merged_from_txn = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_MERGED_FROM)
->setNewValue(mpull($targets, 'getPHID'));
$editor->applyTransactions(
$task,
array($add_ccs, $merged_from_txn));
return $response;
}
- private function getStrings() {
- switch ($this->type) {
+ private function getStrings($attach_type, $action) {
+ switch ($attach_type) {
case DifferentialRevisionPHIDType::TYPECONST:
$noun = 'Revisions';
$selected = 'created';
break;
case ManiphestTaskPHIDType::TYPECONST:
$noun = 'Tasks';
$selected = 'assigned';
break;
case PhabricatorRepositoryCommitPHIDType::TYPECONST:
$noun = 'Commits';
$selected = 'created';
break;
case PholioMockPHIDType::TYPECONST:
$noun = 'Mocks';
$selected = 'created';
break;
}
- switch ($this->action) {
+ switch ($action) {
case self::ACTION_EDGE:
case self::ACTION_ATTACH:
$dialog_title = "Manage Attached {$noun}";
$header_text = "Currently Attached {$noun}";
$button_text = "Save {$noun}";
$instructions = null;
break;
case self::ACTION_MERGE:
$dialog_title = 'Merge Duplicate Tasks';
$header_text = 'Tasks To Merge';
$button_text = "Merge {$noun}";
$instructions =
'These tasks will be merged into the current task and then closed. '.
'The current task will grow stronger.';
break;
case self::ACTION_DEPENDENCIES:
$dialog_title = 'Edit Dependencies';
$header_text = 'Current Dependencies';
$button_text = 'Save Dependencies';
$instructions = null;
break;
case self::ACTION_BLOCKS:
$dialog_title = pht('Edit Blocking Tasks');
$header_text = pht('Current Blocking Tasks');
$button_text = pht('Save Blocking Tasks');
$instructions = null;
break;
}
return array(
'target_plural_noun' => $noun,
'selected' => $selected,
'title' => $dialog_title,
'header' => $header_text,
'button' => $button_text,
'instructions' => $instructions,
);
}
- private function getFilters(array $strings) {
- if ($this->type == PholioMockPHIDType::TYPECONST) {
+ private function getFilters(array $strings, $attach_type) {
+ if ($attach_type == PholioMockPHIDType::TYPECONST) {
$filters = array(
'created' => 'Created By Me',
'all' => 'All '.$strings['target_plural_noun'],
);
} else {
$filters = array(
'assigned' => 'Assigned to Me',
'created' => 'Created By Me',
'open' => 'All Open '.$strings['target_plural_noun'],
'all' => 'All '.$strings['target_plural_noun'],
);
}
return $filters;
}
private function getEdgeType($src_type, $dst_type) {
$t_cmit = PhabricatorRepositoryCommitPHIDType::TYPECONST;
$t_task = ManiphestTaskPHIDType::TYPECONST;
$t_drev = DifferentialRevisionPHIDType::TYPECONST;
$t_mock = PholioMockPHIDType::TYPECONST;
$map = array(
$t_cmit => array(
$t_task => DiffusionCommitHasTaskEdgeType::EDGECONST,
),
$t_task => array(
$t_cmit => ManiphestTaskHasCommitEdgeType::EDGECONST,
$t_task => ManiphestTaskDependsOnTaskEdgeType::EDGECONST,
$t_drev => ManiphestTaskHasRevisionEdgeType::EDGECONST,
$t_mock => ManiphestTaskHasMockEdgeType::EDGECONST,
),
$t_drev => array(
$t_drev => DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST,
$t_task => DifferentialRevisionHasTaskEdgeType::EDGECONST,
),
$t_mock => array(
$t_task => PholioMockHasTaskEdgeType::EDGECONST,
),
);
if (empty($map[$src_type][$dst_type])) {
return null;
}
return $map[$src_type][$dst_type];
}
private function raiseGraphCycleException(PhabricatorEdgeCycleException $ex) {
$cycle = $ex->getCycle();
$handles = $this->loadViewerHandles($cycle);
$names = array();
foreach ($cycle as $cycle_phid) {
$names[] = $handles[$cycle_phid]->getFullName();
}
$names = implode(" \xE2\x86\x92 ", $names);
throw new Exception(
"You can not create that dependency, because it would create a ".
"circular dependency: {$names}.");
}
}
diff --git a/src/applications/search/controller/PhabricatorSearchBaseController.php b/src/applications/search/controller/PhabricatorSearchBaseController.php
index 446406dfea..86573b38bd 100644
--- a/src/applications/search/controller/PhabricatorSearchBaseController.php
+++ b/src/applications/search/controller/PhabricatorSearchBaseController.php
@@ -1,18 +1,24 @@
<?php
abstract class PhabricatorSearchBaseController extends PhabricatorController {
+ const ACTION_ATTACH = 'attach';
+ const ACTION_MERGE = 'merge';
+ const ACTION_DEPENDENCIES = 'dependencies';
+ const ACTION_BLOCKS = 'blocks';
+ const ACTION_EDGE = 'edge';
+
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName('Search');
$page->setBaseURI('/search/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph("\xC2\xBF");
$page->appendChild($view);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
}
diff --git a/src/applications/search/controller/PhabricatorSearchSelectController.php b/src/applications/search/controller/PhabricatorSearchSelectController.php
index 03d3ca4c69..f663cd03d7 100644
--- a/src/applications/search/controller/PhabricatorSearchSelectController.php
+++ b/src/applications/search/controller/PhabricatorSearchSelectController.php
@@ -1,79 +1,86 @@
<?php
final class PhabricatorSearchSelectController
extends PhabricatorSearchBaseController {
- private $type;
-
- public function willProcessRequest(array $data) {
- $this->type = $data['type'];
- }
-
- public function processRequest() {
- $request = $this->getRequest();
+ public function handleRequest(AphrontRequest $request) {
$user = $request->getUser();
+ $type = $request->getURIData('type');
+ $action = $request->getURIData('action');
$query = new PhabricatorSavedQuery();
$query_str = $request->getStr('query');
$query->setEngineClassName('PhabricatorSearchApplicationSearchEngine');
$query->setParameter('query', $query_str);
- $query->setParameter('types', array($this->type));
+ $query->setParameter('types', array($type));
$status_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN;
switch ($request->getStr('filter')) {
case 'assigned':
$query->setParameter('ownerPHIDs', array($user->getPHID()));
$query->setParameter('statuses', array($status_open));
break;
case 'created';
$query->setParameter('authorPHIDs', array($user->getPHID()));
// TODO - if / when we allow pholio mocks to be archived, etc
// update this
- if ($this->type != PholioMockPHIDType::TYPECONST) {
+ if ($type != PholioMockPHIDType::TYPECONST) {
$query->setParameter('statuses', array($status_open));
}
break;
case 'open':
$query->setParameter('statuses', array($status_open));
break;
}
$query->setParameter('excludePHIDs', array($request->getStr('exclude')));
+ $capabilities = array(PhabricatorPolicyCapability::CAN_VIEW);
+ switch ($action) {
+ case self::ACTION_MERGE:
+ $capabilities[] = PhabricatorPolicyCapability::CAN_EDIT;
+ break;
+ default:
+ break;
+ }
+
$results = id(new PhabricatorSearchDocumentQuery())
->setViewer($user)
+ ->requireObjectCapabilities($capabilities)
->withSavedQuery($query)
->setOffset(0)
->setLimit(100)
->execute();
$phids = array_fill_keys(mpull($results, 'getPHID'), true);
- $phids += $this->queryObjectNames($query_str);
+ $phids += $this->queryObjectNames($query_str, $capabilities);
$phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids);
$data = array();
foreach ($handles as $handle) {
$view = new PhabricatorHandleObjectSelectorDataView($handle);
$data[] = $view->renderData();
}
return id(new AphrontAjaxResponse())->setContent($data);
}
- private function queryObjectNames($query) {
- $viewer = $this->getRequest()->getUser();
+ private function queryObjectNames($query, $capabilities) {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
$objects = id(new PhabricatorObjectQuery())
->setViewer($viewer)
- ->withTypes(array($this->type))
+ ->requireCapabilities($capabilities)
+ ->withTypes(array($request->getURIData('type')))
->withNames(array($query))
->execute();
return mpull($objects, 'getPHID');
}
}
diff --git a/src/applications/search/query/PhabricatorSearchDocumentQuery.php b/src/applications/search/query/PhabricatorSearchDocumentQuery.php
index b5591d8eca..903d40dd5a 100644
--- a/src/applications/search/query/PhabricatorSearchDocumentQuery.php
+++ b/src/applications/search/query/PhabricatorSearchDocumentQuery.php
@@ -1,84 +1,98 @@
<?php
final class PhabricatorSearchDocumentQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $savedQuery;
+ private $objectCapabilities;
public function withSavedQuery(PhabricatorSavedQuery $query) {
$this->savedQuery = $query;
return $this;
}
+ public function requireObjectCapabilities(array $capabilities) {
+ $this->objectCapabilities = $capabilities;
+ return $this;
+ }
+
+ protected function getRequiredObjectCapabilities() {
+ if ($this->objectCapabilities) {
+ return $this->objectCapabilities;
+ }
+ return $this->getRequiredCapabilities();
+ }
+
protected function loadPage() {
$phids = $this->loadDocumentPHIDsWithoutPolicyChecks();
$handles = id(new PhabricatorHandleQuery())
->setViewer($this->getViewer())
+ ->requireObjectCapabilities($this->getRequiredObjectCapabilities())
->withPHIDs($phids)
->execute();
// Retain engine order.
$handles = array_select_keys($handles, $phids);
return $handles;
}
protected function willFilterPage(array $handles) {
// NOTE: This is used by the object selector dialog to exclude the object
// you're looking at, so that, e.g., a task can't be set as a dependency
// of itself in the UI.
// TODO: Remove this after object selection moves to ApplicationSearch.
$exclude = array();
if ($this->savedQuery) {
$exclude_phids = $this->savedQuery->getParameter('excludePHIDs', array());
$exclude = array_fuse($exclude_phids);
}
foreach ($handles as $key => $handle) {
if (!$handle->isComplete()) {
unset($handles[$key]);
continue;
}
if ($handle->getPolicyFiltered()) {
unset($handles[$key]);
continue;
}
if (isset($exclude[$handle->getPHID()])) {
unset($handles[$key]);
continue;
}
}
return $handles;
}
public function loadDocumentPHIDsWithoutPolicyChecks() {
$query = id(clone($this->savedQuery))
->setParameter('offset', $this->getOffset())
->setParameter('limit', $this->getRawResultLimit());
$engine = PhabricatorSearchEngineSelector::newSelector()->newEngine();
return $engine->executeSearch($query);
}
public function getQueryApplicationClass() {
return 'PhabricatorSearchApplication';
}
protected function getResultCursor($result) {
throw new Exception(
pht(
'This query does not support cursor paging; it must be offset '.
'paged.'));
}
protected function nextPage(array $page) {
$this->setOffset($this->getOffset() + count($page));
return $this;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Dec 3, 7:35 AM (9 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
433218
Default Alt Text
(23 KB)

Event Timeline