diff --git a/resources/sql/patches/20130531.filekeys.sql b/resources/sql/patches/20130531.filekeys.sql new file mode 100644 index 0000000000..5d0914aa26 --- /dev/null +++ b/resources/sql/patches/20130531.filekeys.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_file.file + ADD KEY `key_dateCreated` (dateCreated); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5fe04a05b1..19a8917d7b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1006,6 +1006,7 @@ phutil_register_library_map(array( 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', + 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', @@ -2812,8 +2813,13 @@ phutil_register_library_map(array( 'PhabricatorFileInfoController' => 'PhabricatorFileController', 'PhabricatorFileLinkListView' => 'AphrontView', 'PhabricatorFileLinkView' => 'AphrontView', - 'PhabricatorFileListController' => 'PhabricatorFileController', + 'PhabricatorFileListController' => + array( + 0 => 'PhabricatorFileController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileShortcutController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', diff --git a/src/applications/files/application/PhabricatorApplicationFiles.php b/src/applications/files/application/PhabricatorApplicationFiles.php index 5d7d45258b..568fa00e97 100644 --- a/src/applications/files/application/PhabricatorApplicationFiles.php +++ b/src/applications/files/application/PhabricatorApplicationFiles.php @@ -38,8 +38,7 @@ final class PhabricatorApplicationFiles extends PhabricatorApplication { return array( '/F(?P[1-9]\d*)' => 'PhabricatorFileShortcutController', '/file/' => array( - '' => 'PhabricatorFileListController', - 'filter/(?P\w+)/' => 'PhabricatorFileListController', + '(query/(?P[^/]+)/)?' => 'PhabricatorFileListController', 'upload/' => 'PhabricatorFileUploadController', 'dropupload/' => 'PhabricatorFileDropUploadController', 'delete/(?P[1-9]\d*)/' => 'PhabricatorFileDeleteController', diff --git a/src/applications/files/controller/PhabricatorFileController.php b/src/applications/files/controller/PhabricatorFileController.php index 9c6a1a68b1..0ba079807f 100644 --- a/src/applications/files/controller/PhabricatorFileController.php +++ b/src/applications/files/controller/PhabricatorFileController.php @@ -29,13 +29,9 @@ abstract class PhabricatorFileController extends PhabricatorController { $menu->newLink(pht('Upload File'), $this->getApplicationURI('/upload/')); } - $menu->newLabel(pht('Filters')); - - $menu->newLink(pht('My Files'), $this->getApplicationURI('filter/my/')) - ->setKey('my'); - - $menu->newLink(pht('All Files'), $this->getApplicationURI('filter/all/')) - ->setKey('all'); + id(new PhabricatorFileSearchEngine()) + ->setViewer($this->getRequest()->getUser()) + ->addNavigationItems($menu); return $menu; } diff --git a/src/applications/files/controller/PhabricatorFileListController.php b/src/applications/files/controller/PhabricatorFileListController.php index 5f6ee24013..d3c1322607 100644 --- a/src/applications/files/controller/PhabricatorFileListController.php +++ b/src/applications/files/controller/PhabricatorFileListController.php @@ -1,83 +1,40 @@ filter = $filter; - return $this; - } - - private function getFilter() { - return $this->filter; + public function shouldAllowPublic() { + return true; } public function willProcessRequest(array $data) { - $this->setFilter(idx($data, 'filter', 'my')); + $this->key = idx($data, 'key', 'authored'); } public function processRequest() { $request = $this->getRequest(); - $user = $request->getUser(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->key) + ->setSearchEngine(new PhabricatorFileSearchEngine()) + ->setNavigation($this->buildSideNavView()); - $pager = id(new AphrontCursorPagerView()) - ->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, - )); + return $this->delegateToController($controller); } - private function buildFileList(array $files, array $highlighted_ids) { + public function renderResultsList(array $files) { assert_instances_of($files, 'PhabricatorFile'); $request = $this->getRequest(); $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); $list_view = id(new PhabricatorObjectItemListView()) @@ -118,6 +75,8 @@ final class PhabricatorFileListController extends PhabricatorFileController { $list_view->addItem($item); } + $list_view->appendChild(new PhabricatorGlobalUploadTargetView()); + return $list_view; } diff --git a/src/applications/files/query/PhabricatorFileQuery.php b/src/applications/files/query/PhabricatorFileQuery.php index cd6ba68641..7ce622ead5 100644 --- a/src/applications/files/query/PhabricatorFileQuery.php +++ b/src/applications/files/query/PhabricatorFileQuery.php @@ -8,6 +8,8 @@ final class PhabricatorFileQuery private $authorPHIDs; private $explicitUploads; private $transforms; + private $dateCreatedAfter; + private $dateCreatedBefore; public function withIDs(array $ids) { $this->ids = $ids; @@ -24,6 +26,16 @@ final class PhabricatorFileQuery 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, * 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)); } + 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); } diff --git a/src/applications/files/query/PhabricatorFileSearchEngine.php b/src/applications/files/query/PhabricatorFileSearchEngine.php new file mode 100644 index 0000000000..cef9c566b2 --- /dev/null +++ b/src/applications/files/query/PhabricatorFileSearchEngine.php @@ -0,0 +1,113 @@ +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); + } + +} diff --git a/src/applications/macro/controller/PhabricatorMacroController.php b/src/applications/macro/controller/PhabricatorMacroController.php index 5f0c698364..74e5950781 100644 --- a/src/applications/macro/controller/PhabricatorMacroController.php +++ b/src/applications/macro/controller/PhabricatorMacroController.php @@ -16,7 +16,7 @@ abstract class PhabricatorMacroController id(new PhabricatorMacroSearchEngine()) ->setViewer($this->getRequest()->getUser()) - ->addNavigationItems($nav); + ->addNavigationItems($nav->getMenu()); return $nav; } diff --git a/src/applications/paste/controller/PhabricatorPasteController.php b/src/applications/paste/controller/PhabricatorPasteController.php index 5d4db78f8a..5e661a25a4 100644 --- a/src/applications/paste/controller/PhabricatorPasteController.php +++ b/src/applications/paste/controller/PhabricatorPasteController.php @@ -14,7 +14,7 @@ abstract class PhabricatorPasteController extends PhabricatorController { id(new PhabricatorPasteSearchEngine()) ->setViewer($user) - ->addNavigationItems($nav); + ->addNavigationItems($nav->getMenu()); $nav->selectFilter(null); diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index 6bace298b0..9ad79215d7 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -106,10 +106,10 @@ abstract class PhabricatorApplicationSearchEngine { } - public function addNavigationItems(AphrontSideNavFilterView $nav) { + public function addNavigationItems(PhabricatorMenuView $menu) { $viewer = $this->requireViewer(); - $nav->addLabel(pht('Queries')); + $menu->newLabel(pht('Queries')); $named_queries = id(new PhabricatorNamedQueryQuery()) ->setViewer($viewer) @@ -122,15 +122,15 @@ abstract class PhabricatorApplicationSearchEngine { foreach ($named_queries as $query) { $key = $query->getQueryKey(); $uri = $this->getQueryResultsPageURI($key); - $nav->addFilter('query/'.$key, $query->getQueryName(), $uri); + $menu->newLink($query->getQueryName(), $uri, 'query/'.$key); } $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'); - $nav->addFilter('query/advanced', pht('Advanced Search'), $advanced_uri); + $menu->newLink(pht('Advanced Search'), $advanced_uri, 'query/advanced'); return $this; } diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index a242f3d714..b7ab25ba68 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1338,6 +1338,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { 'type' => 'sql', 'name' => $this->getPatchPath('20130530.pastekeys.sql'), ), + '20130531.filekeys.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20130531.filekeys.sql'), + ), ); } } diff --git a/src/view/layout/PhabricatorObjectItemListView.php b/src/view/layout/PhabricatorObjectItemListView.php index 74b0dc233f..33f61bcbb6 100644 --- a/src/view/layout/PhabricatorObjectItemListView.php +++ b/src/view/layout/PhabricatorObjectItemListView.php @@ -93,6 +93,7 @@ final class PhabricatorObjectItemListView extends AphrontView { $header, $items, $pager, + $this->renderChildren(), )); }