mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-01 19:22:42 +01:00
Implement ApplicationSearch in Files
Summary: Ref T2625. Ref T1163. A couple of small generalization nudges, but this is almost entirely straightforward. Test Plan: Executed various File queries. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T1163, T2625 Differential Revision: https://secure.phabricator.com/D6091
This commit is contained in:
parent
a92fc74ef1
commit
3aae972406
12 changed files with 185 additions and 79 deletions
2
resources/sql/patches/20130531.filekeys.sql
Normal file
2
resources/sql/patches/20130531.filekeys.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_file.file
|
||||||
|
ADD KEY `key_dateCreated` (dateCreated);
|
|
@ -1006,6 +1006,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
|
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
|
||||||
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
|
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
|
||||||
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
|
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
|
||||||
|
'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php',
|
||||||
'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php',
|
'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php',
|
||||||
'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php',
|
'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php',
|
||||||
'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php',
|
'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php',
|
||||||
|
@ -2812,8 +2813,13 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorFileInfoController' => 'PhabricatorFileController',
|
'PhabricatorFileInfoController' => 'PhabricatorFileController',
|
||||||
'PhabricatorFileLinkListView' => 'AphrontView',
|
'PhabricatorFileLinkListView' => 'AphrontView',
|
||||||
'PhabricatorFileLinkView' => 'AphrontView',
|
'PhabricatorFileLinkView' => 'AphrontView',
|
||||||
'PhabricatorFileListController' => 'PhabricatorFileController',
|
'PhabricatorFileListController' =>
|
||||||
|
array(
|
||||||
|
0 => 'PhabricatorFileController',
|
||||||
|
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
|
||||||
|
),
|
||||||
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorFileShortcutController' => 'PhabricatorFileController',
|
'PhabricatorFileShortcutController' => 'PhabricatorFileController',
|
||||||
'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
|
'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
|
||||||
'PhabricatorFileStorageConfigurationException' => 'Exception',
|
'PhabricatorFileStorageConfigurationException' => 'Exception',
|
||||||
|
|
|
@ -38,8 +38,7 @@ final class PhabricatorApplicationFiles extends PhabricatorApplication {
|
||||||
return array(
|
return array(
|
||||||
'/F(?P<id>[1-9]\d*)' => 'PhabricatorFileShortcutController',
|
'/F(?P<id>[1-9]\d*)' => 'PhabricatorFileShortcutController',
|
||||||
'/file/' => array(
|
'/file/' => array(
|
||||||
'' => 'PhabricatorFileListController',
|
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController',
|
||||||
'filter/(?P<filter>\w+)/' => 'PhabricatorFileListController',
|
|
||||||
'upload/' => 'PhabricatorFileUploadController',
|
'upload/' => 'PhabricatorFileUploadController',
|
||||||
'dropupload/' => 'PhabricatorFileDropUploadController',
|
'dropupload/' => 'PhabricatorFileDropUploadController',
|
||||||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
||||||
|
|
|
@ -29,13 +29,9 @@ abstract class PhabricatorFileController extends PhabricatorController {
|
||||||
$menu->newLink(pht('Upload File'), $this->getApplicationURI('/upload/'));
|
$menu->newLink(pht('Upload File'), $this->getApplicationURI('/upload/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$menu->newLabel(pht('Filters'));
|
id(new PhabricatorFileSearchEngine())
|
||||||
|
->setViewer($this->getRequest()->getUser())
|
||||||
$menu->newLink(pht('My Files'), $this->getApplicationURI('filter/my/'))
|
->addNavigationItems($menu);
|
||||||
->setKey('my');
|
|
||||||
|
|
||||||
$menu->newLink(pht('All Files'), $this->getApplicationURI('filter/all/'))
|
|
||||||
->setKey('all');
|
|
||||||
|
|
||||||
return $menu;
|
return $menu;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,83 +1,40 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorFileListController extends PhabricatorFileController {
|
final class PhabricatorFileListController extends PhabricatorFileController
|
||||||
|
implements PhabricatorApplicationSearchResultsControllerInterface {
|
||||||
|
|
||||||
private $filter;
|
private $key;
|
||||||
|
|
||||||
private function setFilter($filter) {
|
public function shouldAllowPublic() {
|
||||||
$this->filter = $filter;
|
return true;
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getFilter() {
|
|
||||||
return $this->filter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function willProcessRequest(array $data) {
|
||||||
$this->setFilter(idx($data, 'filter', 'my'));
|
$this->key = idx($data, 'key', 'authored');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$controller = id(new PhabricatorApplicationSearchController($request))
|
||||||
|
->setQueryKey($this->key)
|
||||||
|
->setSearchEngine(new PhabricatorFileSearchEngine())
|
||||||
|
->setNavigation($this->buildSideNavView());
|
||||||
|
|
||||||
$pager = id(new AphrontCursorPagerView())
|
return $this->delegateToController($controller);
|
||||||
->readFromRequest($request);
|
|
||||||
|
|
||||||
$query = id(new PhabricatorFileQuery())
|
|
||||||
->setViewer($user);
|
|
||||||
|
|
||||||
switch ($this->getFilter()) {
|
|
||||||
case 'my':
|
|
||||||
$query->withAuthorPHIDs(array($user->getPHID()));
|
|
||||||
$query->showOnlyExplicitUploads(true);
|
|
||||||
$header = pht('Files You Uploaded');
|
|
||||||
break;
|
|
||||||
case 'all':
|
|
||||||
default:
|
|
||||||
$header = pht('All Files');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = $query->executeWithCursorPager($pager);
|
|
||||||
$this->loadHandles(mpull($files, 'getAuthorPHID'));
|
|
||||||
|
|
||||||
$highlighted = $request->getStrList('h');
|
|
||||||
$file_list = $this->buildFileList($files, $highlighted);
|
|
||||||
|
|
||||||
$side_nav = $this->buildSideNavView();
|
|
||||||
$side_nav->selectFilter($this->getFilter());
|
|
||||||
|
|
||||||
$side_nav->appendChild(
|
|
||||||
array(
|
|
||||||
$file_list,
|
|
||||||
$pager,
|
|
||||||
new PhabricatorGlobalUploadTargetView(),
|
|
||||||
));
|
|
||||||
|
|
||||||
$side_nav->setCrumbs(
|
|
||||||
$this
|
|
||||||
->buildApplicationCrumbs()
|
|
||||||
->addCrumb(
|
|
||||||
id(new PhabricatorCrumbView())
|
|
||||||
->setName($header)
|
|
||||||
->setHref($request->getRequestURI())));
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
|
||||||
$side_nav,
|
|
||||||
array(
|
|
||||||
'title' => 'Files',
|
|
||||||
'device' => true,
|
|
||||||
'dust' => true,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildFileList(array $files, array $highlighted_ids) {
|
public function renderResultsList(array $files) {
|
||||||
assert_instances_of($files, 'PhabricatorFile');
|
assert_instances_of($files, 'PhabricatorFile');
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$highlighted_ids = $request->getStrList('h');
|
||||||
|
$this->loadHandles(mpull($files, 'getAuthorPHID'));
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
$highlighted_ids = array_fill_keys($highlighted_ids, true);
|
$highlighted_ids = array_fill_keys($highlighted_ids, true);
|
||||||
|
|
||||||
$list_view = id(new PhabricatorObjectItemListView())
|
$list_view = id(new PhabricatorObjectItemListView())
|
||||||
|
@ -118,6 +75,8 @@ final class PhabricatorFileListController extends PhabricatorFileController {
|
||||||
$list_view->addItem($item);
|
$list_view->addItem($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$list_view->appendChild(new PhabricatorGlobalUploadTargetView());
|
||||||
|
|
||||||
return $list_view;
|
return $list_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ final class PhabricatorFileQuery
|
||||||
private $authorPHIDs;
|
private $authorPHIDs;
|
||||||
private $explicitUploads;
|
private $explicitUploads;
|
||||||
private $transforms;
|
private $transforms;
|
||||||
|
private $dateCreatedAfter;
|
||||||
|
private $dateCreatedBefore;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -24,6 +26,16 @@ final class PhabricatorFileQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withDateCreatedBefore($date_created_before) {
|
||||||
|
$this->dateCreatedBefore = $date_created_before;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withDateCreatedAfter($date_created_after) {
|
||||||
|
$this->dateCreatedAfter = $date_created_after;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select files which are transformations of some other file. For example,
|
* Select files which are transformations of some other file. For example,
|
||||||
* you can use this query to find previously generated thumbnails of an image
|
* you can use this query to find previously generated thumbnails of an image
|
||||||
|
@ -156,6 +168,20 @@ final class PhabricatorFileQuery
|
||||||
$where[] = qsprintf($conn_r, '(%Q)', implode(') OR (', $clauses));
|
$where[] = qsprintf($conn_r, '(%Q)', implode(') OR (', $clauses));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedAfter) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'f.dateCreated >= %d',
|
||||||
|
$this->dateCreatedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->dateCreatedBefore) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'f.dateCreated <= %d',
|
||||||
|
$this->dateCreatedBefore);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
113
src/applications/files/query/PhabricatorFileSearchEngine.php
Normal file
113
src/applications/files/query/PhabricatorFileSearchEngine.php
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorFileSearchEngine
|
||||||
|
extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
|
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||||
|
$saved = new PhabricatorSavedQuery();
|
||||||
|
$saved->setParameter(
|
||||||
|
'authorPHIDs',
|
||||||
|
array_values($request->getArr('authors')));
|
||||||
|
|
||||||
|
$saved->setParameter('explicit', $request->getBool('explicit'));
|
||||||
|
$saved->setParameter('createdStart', $request->getStr('createdStart'));
|
||||||
|
$saved->setParameter('createdEnd', $request->getStr('createdEnd'));
|
||||||
|
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||||
|
$query = id(new PhabricatorFileQuery())
|
||||||
|
->withAuthorPHIDs($saved->getParameter('authorPHIDs', array()));
|
||||||
|
|
||||||
|
if ($saved->getParameter('explicit')) {
|
||||||
|
$query->showOnlyExplicitUploads(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = $this->parseDateTime($saved->getParameter('createdStart'));
|
||||||
|
$end = $this->parseDateTime($saved->getParameter('createdEnd'));
|
||||||
|
|
||||||
|
if ($start) {
|
||||||
|
$query->withDateCreatedAfter($start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end) {
|
||||||
|
$query->withDateCreatedBefore($end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSearchForm(
|
||||||
|
AphrontFormView $form,
|
||||||
|
PhabricatorSavedQuery $saved_query) {
|
||||||
|
|
||||||
|
$phids = $saved_query->getParameter('authorPHIDs', array());
|
||||||
|
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||||
|
->setViewer($this->requireViewer())
|
||||||
|
->loadHandles();
|
||||||
|
$author_tokens = mpull($handles, 'getFullName', 'getPHID');
|
||||||
|
|
||||||
|
$explicit = $saved_query->getParameter('explicit');
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setDatasource('/typeahead/common/users/')
|
||||||
|
->setName('authors')
|
||||||
|
->setLabel(pht('Authors'))
|
||||||
|
->setValue($author_tokens))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormCheckboxControl())
|
||||||
|
->addCheckbox(
|
||||||
|
'explicit',
|
||||||
|
1,
|
||||||
|
pht('Show only manually uploaded files.'),
|
||||||
|
$explicit));
|
||||||
|
|
||||||
|
$this->buildDateRange(
|
||||||
|
$form,
|
||||||
|
$saved_query,
|
||||||
|
'createdStart',
|
||||||
|
pht('Created After'),
|
||||||
|
'createdEnd',
|
||||||
|
pht('Created Before'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getURI($path) {
|
||||||
|
return '/file/'.$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuiltinQueryNames() {
|
||||||
|
$names = array();
|
||||||
|
|
||||||
|
if ($this->requireViewer()->isLoggedIn()) {
|
||||||
|
$names['authored'] = pht('Authored');
|
||||||
|
}
|
||||||
|
|
||||||
|
$names += array(
|
||||||
|
'all' => pht('All'),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
|
|
||||||
|
$query = $this->newSavedQuery();
|
||||||
|
$query->setQueryKey($query_key);
|
||||||
|
|
||||||
|
switch ($query_key) {
|
||||||
|
case 'all':
|
||||||
|
return $query;
|
||||||
|
case 'authored':
|
||||||
|
$author_phid = array($this->requireViewer()->getPHID());
|
||||||
|
return $query
|
||||||
|
->setParameter('authorPHIDs', $author_phid)
|
||||||
|
->setParameter('explicit', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ abstract class PhabricatorMacroController
|
||||||
|
|
||||||
id(new PhabricatorMacroSearchEngine())
|
id(new PhabricatorMacroSearchEngine())
|
||||||
->setViewer($this->getRequest()->getUser())
|
->setViewer($this->getRequest()->getUser())
|
||||||
->addNavigationItems($nav);
|
->addNavigationItems($nav->getMenu());
|
||||||
|
|
||||||
return $nav;
|
return $nav;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ abstract class PhabricatorPasteController extends PhabricatorController {
|
||||||
|
|
||||||
id(new PhabricatorPasteSearchEngine())
|
id(new PhabricatorPasteSearchEngine())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->addNavigationItems($nav);
|
->addNavigationItems($nav->getMenu());
|
||||||
|
|
||||||
$nav->selectFilter(null);
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
|
|
|
@ -106,10 +106,10 @@ abstract class PhabricatorApplicationSearchEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function addNavigationItems(AphrontSideNavFilterView $nav) {
|
public function addNavigationItems(PhabricatorMenuView $menu) {
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$nav->addLabel(pht('Queries'));
|
$menu->newLabel(pht('Queries'));
|
||||||
|
|
||||||
$named_queries = id(new PhabricatorNamedQueryQuery())
|
$named_queries = id(new PhabricatorNamedQueryQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
|
@ -122,15 +122,15 @@ abstract class PhabricatorApplicationSearchEngine {
|
||||||
foreach ($named_queries as $query) {
|
foreach ($named_queries as $query) {
|
||||||
$key = $query->getQueryKey();
|
$key = $query->getQueryKey();
|
||||||
$uri = $this->getQueryResultsPageURI($key);
|
$uri = $this->getQueryResultsPageURI($key);
|
||||||
$nav->addFilter('query/'.$key, $query->getQueryName(), $uri);
|
$menu->newLink($query->getQueryName(), $uri, 'query/'.$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
$manage_uri = $this->getQueryManagementURI();
|
$manage_uri = $this->getQueryManagementURI();
|
||||||
$nav->addFilter('query/edit', pht('Edit Queries...'), $manage_uri);
|
$menu->newLink(pht('Edit Queries...'), $manage_uri, 'query/edit');
|
||||||
|
|
||||||
$nav->addLabel(pht('Search'));
|
$menu->newLabel(pht('Search'));
|
||||||
$advanced_uri = $this->getQueryResultsPageURI('advanced');
|
$advanced_uri = $this->getQueryResultsPageURI('advanced');
|
||||||
$nav->addFilter('query/advanced', pht('Advanced Search'), $advanced_uri);
|
$menu->newLink(pht('Advanced Search'), $advanced_uri, 'query/advanced');
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1338,6 +1338,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('20130530.pastekeys.sql'),
|
'name' => $this->getPatchPath('20130530.pastekeys.sql'),
|
||||||
),
|
),
|
||||||
|
'20130531.filekeys.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20130531.filekeys.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ final class PhabricatorObjectItemListView extends AphrontView {
|
||||||
$header,
|
$header,
|
||||||
$items,
|
$items,
|
||||||
$pager,
|
$pager,
|
||||||
|
$this->renderChildren(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue