diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7880d6a589..3186ce67dc 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1533,6 +1533,7 @@ phutil_register_library_map(array( 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php', 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', 'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php', + 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', 'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', @@ -3482,7 +3483,11 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteCreateController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', - 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlowvoteListController' => + array( + 0 => 'PhabricatorSlowvoteController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePoll' => array( @@ -3490,7 +3495,8 @@ phutil_register_library_map(array( 1 => 'PhabricatorPolicyInterface', ), 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', - 'PhabricatorSlowvoteQuery' => 'PhabricatorPolicyAwareCursorPagedQuery', + 'PhabricatorSlowvoteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableExample' => 'PhabricatorUIExample', diff --git a/src/applications/slowvote/application/PhabricatorApplicationSlowvote.php b/src/applications/slowvote/application/PhabricatorApplicationSlowvote.php index 4802e1470d..bec1a90743 100644 --- a/src/applications/slowvote/application/PhabricatorApplicationSlowvote.php +++ b/src/applications/slowvote/application/PhabricatorApplicationSlowvote.php @@ -40,7 +40,8 @@ final class PhabricatorApplicationSlowvote extends PhabricatorApplication { return array( '/V(?P[1-9]\d*)' => 'PhabricatorSlowvotePollController', '/vote/' => array( - '(?:view/(?P\w+)/)?' => 'PhabricatorSlowvoteListController', + '(?:query/(?P[^/]+)/)?' + => 'PhabricatorSlowvoteListController', 'create/' => 'PhabricatorSlowvoteCreateController', '(?P[1-9]\d*)/' => 'PhabricatorSlowvoteVoteController', ), diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteController.php index 34bd2ec568..25e0ba8b83 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteController.php @@ -5,46 +5,28 @@ */ abstract class PhabricatorSlowvoteController extends PhabricatorController { - const VIEW_ALL = 'all'; - const VIEW_CREATED = 'created'; - const VIEW_VOTED = 'voted'; + public function buildSideNavView($for_app = false) { + $user = $this->getRequest()->getUser(); - public function buildStandardPageResponse($view, array $data) { - $page = $this->buildStandardPageView(); - - $page->setApplicationName(pht('Slowvote')); - $page->setBaseURI('/vote/'); - $page->setTitle(idx($data, 'title')); - $page->setGlyph("\xE2\x9C\x94"); - - $page->appendChild($view); - - $response = new AphrontWebpageResponse(); - return $response->setContent($page->render()); - } - - public function buildSideNavView($filter = null, $for_app = false) { - - $views = $this->getViews(); - $side_nav = new AphrontSideNavFilterView(); - $side_nav->setBaseURI(new PhutilURI('/vote/view/')); - foreach ($views as $key => $name) { - $side_nav->addFilter($key, $name); - } - if ($filter) { - $side_nav->selectFilter($filter, null); - } + $nav = new AphrontSideNavFilterView(); + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); if ($for_app) { - $side_nav->addFilter('', pht('Create Question'), + $nav->addFilter('', pht('Create Poll'), $this->getApplicationURI('create/')); } - return $side_nav; + id(new PhabricatorSlowvoteSearchEngine()) + ->setViewer($user) + ->addNavigationItems($nav->getMenu()); + + $nav->selectFilter(null); + + return $nav; } public function buildApplicationMenu() { - return $this->buildSideNavView(null, true)->getMenu(); + return $this->buildSideNavView(true)->getMenu(); } public function buildApplicationCrumbs() { @@ -52,19 +34,11 @@ abstract class PhabricatorSlowvoteController extends PhabricatorController { $crumbs->addAction( id(new PHUIListItemView()) - ->setName(pht('Create Question')) + ->setName(pht('Create Poll')) ->setHref($this->getApplicationURI('create/')) ->setIcon('create')); return $crumbs; } - public function getViews() { - return array( - self::VIEW_ALL => pht('All Slowvotes'), - self::VIEW_CREATED => pht('Created'), - self::VIEW_VOTED => pht('Voted In'), - ); - } - } diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteListController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteListController.php index 072cc13d13..87fb9ca2c9 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteListController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteListController.php @@ -4,154 +4,63 @@ * @group slowvote */ final class PhabricatorSlowvoteListController - extends PhabricatorSlowvoteController { + extends PhabricatorSlowvoteController + implements PhabricatorApplicationSearchResultsControllerInterface { - private $view; + private $queryKey; + + public function shouldAllowPublic() { + return true; + } public function willProcessRequest(array $data) { - $this->view = idx($data, 'view', parent::VIEW_ALL); + $this->queryKey = idx($data, 'queryKey'); } public function processRequest() { - $request = $this->getRequest(); - $user = $request->getUser(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->queryKey) + ->setSearchEngine(new PhabricatorSlowvoteSearchEngine()) + ->setNavigation($this->buildSideNavView()); - $view = $this->view; - $views = $this->getViews(); + return $this->delegateToController($controller); + } - $side_nav = $this->buildSideNavView($view); + public function renderResultsList( + array $polls, + PhabricatorSavedQuery $query) { + assert_instances_of($polls, 'PhabricatorSlowvotePoll'); + $viewer = $this->getRequest()->getUser(); - $pager = new AphrontPagerView(); - $pager->setOffset($request->getInt('page')); - $pager->setURI($request->getRequestURI(), 'page'); - - $polls = $this->loadPolls($pager, $view); + $list = id(new PhabricatorObjectItemListView()) + ->setUser($viewer); $phids = mpull($polls, 'getAuthorPHID'); $handles = $this->loadViewerHandles($phids); - $rows = array(); foreach ($polls as $poll) { - $rows[] = array( - 'V'.$poll->getID(), - phutil_tag( - 'a', - array( - 'href' => '/V'.$poll->getID(), - ), - $poll->getQuestion()), - $handles[$poll->getAuthorPHID()]->renderLink(), - phabricator_date($poll->getDateCreated(), $user), - phabricator_time($poll->getDateCreated(), $user), - ); + $date_created = phabricator_datetime($poll->getDateCreated(), $viewer); + if ($poll->getAuthorPHID()) { + $author = $handles[$poll->getAuthorPHID()]->renderLink(); + } else { + $author = null; + } + + $item = id(new PhabricatorObjectItemView()) + ->setObjectName('V'.$poll->getID()) + ->setHeader($poll->getQuestion()) + ->setHref('/V'.$poll->getID()) + ->addIcon('none', $date_created); + + if ($author) { + $item->addByline(pht('Author: %s', $author)); + } + + $list->addItem($item); } - $table = new AphrontTableView($rows); - $table->setColumnClasses( - array( - '', - 'pri wide', - '', - '', - 'right', - )); - $table->setHeaders( - array( - pht('ID'), - pht('Poll'), - pht('Author'), - pht('Date'), - pht('Time'), - )); - - switch ($view) { - case self::VIEW_ALL: - $table_header = - pht('Slowvotes Not Yet Consumed by the Ravages of Time'); - break; - case self::VIEW_CREATED: - $table_header = - pht('Slowvotes Birthed from Your Noblest of Great Minds'); - break; - case self::VIEW_VOTED: - $table_header = - pht('Slowvotes Within Which You Express Your Mighty Opinion'); - break; - } - - $panel = new AphrontPanelView(); - $panel->setHeader($table_header); - $panel->setNoBackground(); - $panel->appendChild($table); - $panel->appendChild($pager); - - $side_nav->appendChild($panel); - - $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); - $crumbs->addCrumb( - id(new PhabricatorCrumbView()) - ->setName($views[$view]) - ->setHref($this->getApplicationURI())); - $side_nav->setCrumbs($crumbs); - - return $this->buildApplicationPage( - $side_nav, - array( - 'title' => pht('Slowvotes'), - 'device' => true, - )); - } - - private function loadPolls(AphrontPagerView $pager, $view) { - $request = $this->getRequest(); - $user = $request->getUser(); - - $poll = new PhabricatorSlowvotePoll(); - - $conn = $poll->establishConnection('r'); - $offset = $pager->getOffset(); - $limit = $pager->getPageSize() + 1; - - switch ($view) { - case self::VIEW_ALL: - $data = queryfx_all( - $conn, - 'SELECT * FROM %T ORDER BY id DESC LIMIT %d, %d', - $poll->getTableName(), - $offset, - $limit); - break; - case self::VIEW_CREATED: - $data = queryfx_all( - $conn, - 'SELECT * FROM %T WHERE authorPHID = %s ORDER BY id DESC - LIMIT %d, %d', - $poll->getTableName(), - $user->getPHID(), - $offset, - $limit); - break; - case self::VIEW_VOTED: - $choice = new PhabricatorSlowvoteChoice(); - $data = queryfx_all( - $conn, - 'SELECT p.* FROM %T p JOIN %T o - ON o.pollID = p.id - WHERE o.authorPHID = %s - GROUP BY p.id - ORDER BY p.id DESC - LIMIT %d, %d', - $poll->getTableName(), - $choice->getTableName(), - $user->getPHID(), - $offset, - $limit); - break; - } - - $data = $pager->sliceResults($data); - return $poll->loadAllFromArray($data); + return $list; } } diff --git a/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php b/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php index 855ae44d98..328f6b96f7 100644 --- a/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php +++ b/src/applications/slowvote/query/PhabricatorSlowvoteQuery.php @@ -9,6 +9,7 @@ final class PhabricatorSlowvoteQuery private $ids; private $phids; private $authorPHIDs; + private $withVotesByViewer; public function withIDs($ids) { $this->ids = $ids; @@ -25,14 +26,20 @@ final class PhabricatorSlowvoteQuery return $this; } + public function withVotesByViewer($with_vote) { + $this->withVotesByViewer = $with_vote; + return $this; + } + public function loadPage() { $table = new PhabricatorSlowvotePoll(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, - 'SELECT * FROM %T %Q %Q %Q', + 'SELECT p.* FROM %T p %Q %Q %Q %Q', $table->getTableName(), + $this->buildJoinsClause($conn_r), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); @@ -46,21 +53,21 @@ final class PhabricatorSlowvoteQuery if ($this->ids) { $where[] = qsprintf( $conn_r, - 'id IN (%Ld)', + 'p.id IN (%Ld)', $this->ids); } if ($this->phids) { $where[] = qsprintf( $conn_r, - 'phid IN (%Ls)', + 'p.phid IN (%Ls)', $this->phids); } if ($this->authorPHIDs) { $where[] = qsprintf( $conn_r, - 'authorPHID IN (%Ls)', + 'p.authorPHID IN (%Ls)', $this->authorPHIDs); } @@ -68,4 +75,22 @@ final class PhabricatorSlowvoteQuery return $this->formatWhereClause($where); } + private function buildJoinsClause(AphrontDatabaseConnection $conn_r) { + $joins = array(); + + if ($this->withVotesByViewer) { + $joins[] = qsprintf( + $conn_r, + 'JOIN %T vv ON vv.pollID = p.id AND vv.authorPHID = %s', + id(new PhabricatorSlowvoteChoice())->getTableName(), + $this->getViewer()->getPHID()); + } + + return implode(' ', $joins); + } + + protected function getPagingColumn() { + return 'p.id'; + } + } diff --git a/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php new file mode 100644 index 0000000000..f704b12b3b --- /dev/null +++ b/src/applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php @@ -0,0 +1,90 @@ +setParameter( + 'authorPHIDs', + array_values($request->getArr('authors'))); + + $saved->setParameter('voted', $request->getBool('voted')); + + return $saved; + } + + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { + $query = id(new PhabricatorSlowvoteQuery()) + ->withAuthorPHIDs($saved->getParameter('authorPHIDs', array())); + + if ($saved->getParameter('voted')) { + $query->withVotesByViewer(true); + } + + 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'); + + $voted = $saved_query->getParameter('voted', false); + + $form + ->appendChild( + id(new AphrontFormTokenizerControl()) + ->setDatasource('/typeahead/common/users/') + ->setName('authors') + ->setLabel(pht('Authors')) + ->setValue($author_tokens)) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->addCheckbox( + 'voted', + 1, + pht("Show only polls I've voted in."), + $voted)); + } + + protected function getURI($path) { + return '/vote/'.$path; + } + + public function getBuiltinQueryNames() { + $names = array( + 'all' => pht('All Polls'), + ); + + if ($this->requireViewer()->isLoggedIn()) { + $names['authored'] = pht('Authored'); + $names['voted'] = pht('Voted In'); + } + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + case 'authored': + return $query->setParameter( + 'authorPHIDs', + array($this->requireViewer()->getPHID())); + case 'voted': + return $query->setParameter('voted', true); + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + +}