2014-02-03 21:51:08 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class PhabricatorSearchApplicationSearchEngine
|
|
|
|
extends PhabricatorApplicationSearchEngine {
|
|
|
|
|
2014-06-12 22:22:20 +02:00
|
|
|
public function getResultTypeDescription() {
|
|
|
|
return pht('Fulltext Results');
|
|
|
|
}
|
|
|
|
|
2015-02-05 00:47:48 +01:00
|
|
|
public function getApplicationClassName() {
|
2014-07-23 02:03:09 +02:00
|
|
|
return 'PhabricatorSearchApplication';
|
2014-05-09 21:28:02 +02:00
|
|
|
}
|
|
|
|
|
2014-02-03 21:51:08 +01:00
|
|
|
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
|
|
|
$saved = new PhabricatorSavedQuery();
|
|
|
|
|
2014-02-03 21:52:47 +01:00
|
|
|
$saved->setParameter('query', $request->getStr('query'));
|
|
|
|
$saved->setParameter(
|
|
|
|
'statuses',
|
|
|
|
$this->readListFromRequest($request, 'statuses'));
|
|
|
|
$saved->setParameter(
|
|
|
|
'types',
|
|
|
|
$this->readListFromRequest($request, 'types'));
|
|
|
|
|
|
|
|
$saved->setParameter(
|
|
|
|
'authorPHIDs',
|
|
|
|
$this->readUsersFromRequest($request, 'authorPHIDs'));
|
|
|
|
|
|
|
|
$saved->setParameter(
|
|
|
|
'ownerPHIDs',
|
|
|
|
$this->readUsersFromRequest($request, 'ownerPHIDs'));
|
|
|
|
|
|
|
|
$saved->setParameter(
|
|
|
|
'subscriberPHIDs',
|
2015-04-23 12:34:33 +02:00
|
|
|
$this->readSubscribersFromRequest($request, 'subscriberPHIDs'));
|
2014-02-03 21:52:47 +01:00
|
|
|
|
|
|
|
$saved->setParameter(
|
|
|
|
'projectPHIDs',
|
|
|
|
$this->readPHIDsFromRequest($request, 'projectPHIDs'));
|
|
|
|
|
2014-02-03 21:51:08 +01:00
|
|
|
return $saved;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
2015-04-23 12:07:24 +02:00
|
|
|
$query = new PhabricatorSearchDocumentQuery();
|
|
|
|
|
|
|
|
// Convert the saved query into a resolved form (without typeahead
|
|
|
|
// functions) which the fulltext search engines can execute.
|
|
|
|
$config = clone $saved;
|
|
|
|
$viewer = $this->requireViewer();
|
|
|
|
|
|
|
|
$datasource = id(new PhabricatorPeopleOwnerDatasource())
|
|
|
|
->setViewer($viewer);
|
|
|
|
$owner_phids = $this->readOwnerPHIDs($config);
|
|
|
|
$owner_phids = $datasource->evaluateTokens($owner_phids);
|
|
|
|
foreach ($owner_phids as $key => $phid) {
|
|
|
|
if ($phid == PhabricatorPeopleNoOwnerDatasource::FUNCTION_TOKEN) {
|
|
|
|
$config->setParameter('withUnowned', true);
|
|
|
|
unset($owner_phids[$key]);
|
|
|
|
}
|
2015-04-24 00:44:27 +02:00
|
|
|
if ($phid == PhabricatorPeopleAnyOwnerDatasource::FUNCTION_TOKEN) {
|
|
|
|
$config->setParameter('withAnyOwner', true);
|
|
|
|
unset($owner_phids[$key]);
|
|
|
|
}
|
2015-04-23 12:07:24 +02:00
|
|
|
}
|
|
|
|
$config->setParameter('ownerPHIDs', $owner_phids);
|
|
|
|
|
|
|
|
|
2015-04-23 17:06:46 +02:00
|
|
|
$datasource = id(new PhabricatorPeopleUserFunctionDatasource())
|
2015-04-23 12:07:24 +02:00
|
|
|
->setViewer($viewer);
|
|
|
|
$author_phids = $config->getParameter('authorPHIDs', array());
|
|
|
|
$author_phids = $datasource->evaluateTokens($author_phids);
|
|
|
|
$config->setParameter('authorPHIDs', $author_phids);
|
|
|
|
|
2015-04-23 12:34:33 +02:00
|
|
|
|
|
|
|
$datasource = id(new PhabricatorMetaMTAMailableFunctionDatasource())
|
|
|
|
->setViewer($viewer);
|
|
|
|
$subscriber_phids = $config->getParameter('subscriberPHIDs', array());
|
|
|
|
$subscriber_phids = $datasource->evaluateTokens($subscriber_phids);
|
|
|
|
$config->setParameter('subscriberPHIDs', $subscriber_phids);
|
|
|
|
|
|
|
|
|
2015-04-23 12:07:24 +02:00
|
|
|
$query->withSavedQuery($config);
|
|
|
|
|
2014-02-03 21:51:08 +01:00
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function buildSearchForm(
|
|
|
|
AphrontFormView $form,
|
2014-02-03 21:52:47 +01:00
|
|
|
PhabricatorSavedQuery $saved) {
|
|
|
|
|
|
|
|
$options = array();
|
|
|
|
$author_value = null;
|
|
|
|
$owner_value = null;
|
|
|
|
$subscribers_value = null;
|
|
|
|
$project_value = null;
|
|
|
|
|
|
|
|
$author_phids = $saved->getParameter('authorPHIDs', array());
|
2015-04-23 12:07:24 +02:00
|
|
|
$owner_phids = $this->readOwnerPHIDs($saved);
|
2014-02-03 21:52:47 +01:00
|
|
|
$subscriber_phids = $saved->getParameter('subscriberPHIDs', array());
|
|
|
|
$project_phids = $saved->getParameter('projectPHIDs', array());
|
|
|
|
|
|
|
|
$status_values = $saved->getParameter('statuses', array());
|
|
|
|
$status_values = array_fuse($status_values);
|
|
|
|
|
|
|
|
$statuses = array(
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_OPEN => pht('Open'),
|
|
|
|
PhabricatorSearchRelationship::RELATIONSHIP_CLOSED => pht('Closed'),
|
|
|
|
);
|
|
|
|
$status_control = id(new AphrontFormCheckboxControl())
|
|
|
|
->setLabel(pht('Document Status'));
|
|
|
|
foreach ($statuses as $status => $name) {
|
|
|
|
$status_control->addCheckbox(
|
|
|
|
'statuses[]',
|
|
|
|
$status,
|
|
|
|
$name,
|
|
|
|
isset($status_values[$status]));
|
|
|
|
}
|
|
|
|
|
|
|
|
$type_values = $saved->getParameter('types', array());
|
|
|
|
$type_values = array_fuse($type_values);
|
|
|
|
|
2015-04-23 00:25:34 +02:00
|
|
|
$types_control = id(new AphrontFormTokenizerControl())
|
|
|
|
->setLabel(pht('Document Types'))
|
|
|
|
->setName('types')
|
|
|
|
->setDatasource(new PhabricatorSearchDocumentTypeDatasource())
|
|
|
|
->setValue($type_values);
|
2014-02-03 21:52:47 +01:00
|
|
|
|
|
|
|
$form
|
|
|
|
->appendChild(
|
|
|
|
phutil_tag(
|
|
|
|
'input',
|
|
|
|
array(
|
|
|
|
'type' => 'hidden',
|
|
|
|
'name' => 'jump',
|
|
|
|
'value' => 'no',
|
|
|
|
)))
|
|
|
|
->appendChild(
|
|
|
|
id(new AphrontFormTextControl())
|
|
|
|
->setLabel('Query')
|
|
|
|
->setName('query')
|
|
|
|
->setValue($saved->getParameter('query')))
|
|
|
|
->appendChild($status_control)
|
2015-04-23 00:25:34 +02:00
|
|
|
->appendControl($types_control)
|
2015-03-31 23:10:55 +02:00
|
|
|
->appendControl(
|
2014-02-03 21:52:47 +01:00
|
|
|
id(new AphrontFormTokenizerControl())
|
|
|
|
->setName('authorPHIDs')
|
|
|
|
->setLabel('Authors')
|
2015-04-23 17:06:46 +02:00
|
|
|
->setDatasource(new PhabricatorPeopleUserFunctionDatasource())
|
2015-03-31 23:10:55 +02:00
|
|
|
->setValue($author_phids))
|
|
|
|
->appendControl(
|
2014-02-03 21:52:47 +01:00
|
|
|
id(new AphrontFormTokenizerControl())
|
|
|
|
->setName('ownerPHIDs')
|
|
|
|
->setLabel('Owners')
|
2015-04-23 12:07:24 +02:00
|
|
|
->setDatasource(new PhabricatorPeopleOwnerDatasource())
|
2015-03-31 23:10:55 +02:00
|
|
|
->setValue($owner_phids))
|
|
|
|
->appendControl(
|
2014-02-03 21:52:47 +01:00
|
|
|
id(new AphrontFormTokenizerControl())
|
|
|
|
->setName('subscriberPHIDs')
|
|
|
|
->setLabel('Subscribers')
|
2015-04-23 12:34:33 +02:00
|
|
|
->setDatasource(new PhabricatorMetaMTAMailableFunctionDatasource())
|
2015-03-31 23:10:55 +02:00
|
|
|
->setValue($subscriber_phids))
|
|
|
|
->appendControl(
|
2014-02-03 21:52:47 +01:00
|
|
|
id(new AphrontFormTokenizerControl())
|
|
|
|
->setName('projectPHIDs')
|
|
|
|
->setLabel('In Any Project')
|
2014-07-11 02:28:29 +02:00
|
|
|
->setDatasource(new PhabricatorProjectDatasource())
|
2015-03-31 23:10:55 +02:00
|
|
|
->setValue($project_phids));
|
2014-02-03 21:51:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getURI($path) {
|
|
|
|
return '/search/'.$path;
|
|
|
|
}
|
|
|
|
|
2015-01-06 21:34:51 +01:00
|
|
|
protected function getBuiltinQueryNames() {
|
2014-07-23 02:03:09 +02:00
|
|
|
return array(
|
2014-02-03 21:51:08 +01:00
|
|
|
'all' => pht('All Documents'),
|
2014-02-03 21:52:47 +01:00
|
|
|
'open' => pht('Open Documents'),
|
|
|
|
'open-tasks' => pht('Open Tasks'),
|
2014-02-03 21:51:08 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function buildSavedQueryFromBuiltin($query_key) {
|
|
|
|
$query = $this->newSavedQuery();
|
|
|
|
$query->setQueryKey($query_key);
|
|
|
|
|
|
|
|
switch ($query_key) {
|
|
|
|
case 'all':
|
|
|
|
return $query;
|
2014-02-03 21:52:47 +01:00
|
|
|
case 'open':
|
|
|
|
return $query->setParameter('statuses', array('open'));
|
|
|
|
case 'open-tasks':
|
|
|
|
return $query
|
|
|
|
->setParameter('statuses', array('open'))
|
2014-07-24 00:05:46 +02:00
|
|
|
->setParameter('types', array(ManiphestTaskPHIDType::TYPECONST));
|
2014-02-03 21:51:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
|
|
|
}
|
|
|
|
|
Don't show document types in search for uninstalled applications
Summary:
Fixes T4917. Currently, if a user doesn't have access to, e.g., Phriction, they still get a checkbox in the search results to search for Wiki Documents. Those results will be filtered anyway, so this is confusing at best.
Instead, bind PHID types to applications. This is a relatively tailored fix; some areas for potential future work:
- Go through every PHID type and bind them all to applications. Vaguely nice to have, but doesn't get us anything for now.
- If no searchable application is installed, we don't show you an error state. This isn't currently possible ("People" is always installed) but in the interest of generality we could throw an exception or something at least.
- The elasticserach thing could probably constrain types to visible types, but we don't have a viewer there easily right now.
Test Plan: Uninstalled Phriction, saw the checkbox vanish.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T4917
Differential Revision: https://secure.phabricator.com/D8904
2014-04-30 00:01:50 +02:00
|
|
|
public static function getIndexableDocumentTypes(
|
|
|
|
PhabricatorUser $viewer = null) {
|
|
|
|
|
2014-02-03 21:52:47 +01:00
|
|
|
// TODO: This is inelegant and not very efficient, but gets us reasonable
|
|
|
|
// results. It would be nice to do this more elegantly.
|
|
|
|
|
|
|
|
$indexers = id(new PhutilSymbolLoader())
|
|
|
|
->setAncestorClass('PhabricatorSearchDocumentIndexer')
|
|
|
|
->loadObjects();
|
|
|
|
|
Don't show document types in search for uninstalled applications
Summary:
Fixes T4917. Currently, if a user doesn't have access to, e.g., Phriction, they still get a checkbox in the search results to search for Wiki Documents. Those results will be filtered anyway, so this is confusing at best.
Instead, bind PHID types to applications. This is a relatively tailored fix; some areas for potential future work:
- Go through every PHID type and bind them all to applications. Vaguely nice to have, but doesn't get us anything for now.
- If no searchable application is installed, we don't show you an error state. This isn't currently possible ("People" is always installed) but in the interest of generality we could throw an exception or something at least.
- The elasticserach thing could probably constrain types to visible types, but we don't have a viewer there easily right now.
Test Plan: Uninstalled Phriction, saw the checkbox vanish.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T4917
Differential Revision: https://secure.phabricator.com/D8904
2014-04-30 00:01:50 +02:00
|
|
|
if ($viewer) {
|
|
|
|
$types = PhabricatorPHIDType::getAllInstalledTypes($viewer);
|
|
|
|
} else {
|
|
|
|
$types = PhabricatorPHIDType::getAllTypes();
|
|
|
|
}
|
2014-02-03 21:52:47 +01:00
|
|
|
|
|
|
|
$results = array();
|
|
|
|
foreach ($types as $type) {
|
|
|
|
$typeconst = $type->getTypeConstant();
|
|
|
|
foreach ($indexers as $indexer) {
|
|
|
|
$fake_phid = 'PHID-'.$typeconst.'-fake';
|
|
|
|
if ($indexer->shouldIndexDocumentByPHID($fake_phid)) {
|
|
|
|
$results[$typeconst] = $type->getTypeName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
asort($results);
|
|
|
|
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
2014-05-08 17:24:47 +02:00
|
|
|
public function shouldUseOffsetPaging() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-09 21:28:02 +02:00
|
|
|
protected function renderResultList(
|
|
|
|
array $results,
|
|
|
|
PhabricatorSavedQuery $query,
|
|
|
|
array $handles) {
|
|
|
|
|
|
|
|
$viewer = $this->requireViewer();
|
|
|
|
|
|
|
|
if ($results) {
|
|
|
|
$objects = id(new PhabricatorObjectQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs(mpull($results, 'getPHID'))
|
|
|
|
->execute();
|
|
|
|
|
2015-03-03 16:18:40 +01:00
|
|
|
$list = new PHUIObjectItemListView();
|
2014-05-09 21:28:02 +02:00
|
|
|
foreach ($results as $phid => $handle) {
|
|
|
|
$view = id(new PhabricatorSearchResultView())
|
|
|
|
->setHandle($handle)
|
|
|
|
->setQuery($query)
|
2015-03-03 16:18:40 +01:00
|
|
|
->setObject(idx($objects, $phid))
|
|
|
|
->render();
|
|
|
|
$list->addItem($view);
|
2014-05-09 21:28:02 +02:00
|
|
|
}
|
|
|
|
|
2015-03-03 16:18:40 +01:00
|
|
|
$results = $list;
|
2014-05-09 21:28:02 +02:00
|
|
|
} else {
|
2015-03-03 16:18:40 +01:00
|
|
|
$results = id(new PHUIInfoView())
|
|
|
|
->appendChild(pht('No results returned for that query.'))
|
|
|
|
->setSeverity(PHUIInfoView::SEVERITY_NODATA);
|
2014-05-09 21:28:02 +02:00
|
|
|
}
|
|
|
|
|
2015-03-03 16:18:40 +01:00
|
|
|
return $results;
|
2014-05-09 21:28:02 +02:00
|
|
|
}
|
2014-02-03 21:52:47 +01:00
|
|
|
|
2015-04-23 12:07:24 +02:00
|
|
|
private function readOwnerPHIDs(PhabricatorSavedQuery $saved) {
|
|
|
|
$owner_phids = $saved->getParameter('ownerPHIDs', array());
|
|
|
|
|
|
|
|
// This was an old checkbox from before typeahead functions.
|
|
|
|
if ($saved->getParameter('withUnowned')) {
|
|
|
|
$owner_phids[] = PhabricatorPeopleNoOwnerDatasource::FUNCTION_TOKEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $owner_phids;
|
|
|
|
}
|
|
|
|
|
2014-02-03 21:51:08 +01:00
|
|
|
}
|