diff --git a/src/applications/meta/query/PhabricatorApplicationQuery.php b/src/applications/meta/query/PhabricatorApplicationQuery.php index 940cf6406d..63de1174cf 100644 --- a/src/applications/meta/query/PhabricatorApplicationQuery.php +++ b/src/applications/meta/query/PhabricatorApplicationQuery.php @@ -1,179 +1,173 @@ nameContains = $name_contains; return $this; } public function withInstalled($installed) { $this->installed = $installed; return $this; } public function withPrototypes($prototypes) { $this->prototypes = $prototypes; return $this; } public function withFirstParty($first_party) { $this->firstParty = $first_party; return $this; } public function withUnlisted($unlisted) { $this->unlisted = $unlisted; return $this; } public function withLaunchable($launchable) { $this->launchable = $launchable; return $this; } public function withApplicationEmailSupport($appemails) { $this->applicationEmailSupport = $appemails; return $this; } public function withClasses(array $classes) { $this->classes = $classes; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function setOrder($order) { $this->order = $order; return $this; } protected function loadPage() { $apps = PhabricatorApplication::getAllApplications(); if ($this->classes) { $classes = array_fuse($this->classes); foreach ($apps as $key => $app) { if (empty($classes[get_class($app)])) { unset($apps[$key]); } } } if ($this->phids) { $phids = array_fuse($this->phids); foreach ($apps as $key => $app) { if (empty($phids[$app->getPHID()])) { unset($apps[$key]); } } } if (strlen($this->nameContains)) { foreach ($apps as $key => $app) { if (stripos($app->getName(), $this->nameContains) === false) { unset($apps[$key]); } } } if ($this->installed !== null) { foreach ($apps as $key => $app) { if ($app->isInstalled() != $this->installed) { unset($apps[$key]); } } } if ($this->prototypes !== null) { foreach ($apps as $key => $app) { if ($app->isPrototype() != $this->prototypes) { unset($apps[$key]); } } } if ($this->firstParty !== null) { foreach ($apps as $key => $app) { if ($app->isFirstParty() != $this->firstParty) { unset($apps[$key]); } } } if ($this->unlisted !== null) { foreach ($apps as $key => $app) { if ($app->isUnlisted() != $this->unlisted) { unset($apps[$key]); } } } if ($this->launchable !== null) { foreach ($apps as $key => $app) { if ($app->isLaunchable() != $this->launchable) { unset($apps[$key]); } } } if ($this->applicationEmailSupport !== null) { foreach ($apps as $key => $app) { if ($app->supportsEmailIntegration() != $this->applicationEmailSupport) { unset($apps[$key]); } } } switch ($this->order) { case self::ORDER_NAME: $apps = msort($apps, 'getName'); break; case self::ORDER_APPLICATION: $apps = $apps; break; default: throw new Exception( pht('Unknown order "%s"!', $this->order)); } return $apps; } public function getQueryApplicationClass() { // NOTE: Although this belongs to the "Applications" application, trying // to filter its results just leaves us recursing indefinitely. Users // always have access to applications regardless of other policy settings // anyway. return null; } - protected function getResultCursor($object) { - // TODO: This won't work, but doesn't matter until we write more than 100 - // applications. Since we only have about 70, just avoid fataling for now. - return null; - } - } diff --git a/src/applications/notification/query/PhabricatorNotificationQuery.php b/src/applications/notification/query/PhabricatorNotificationQuery.php index 0063c06e45..6eea54a0de 100644 --- a/src/applications/notification/query/PhabricatorNotificationQuery.php +++ b/src/applications/notification/query/PhabricatorNotificationQuery.php @@ -1,124 +1,169 @@ userPHIDs = $user_phids; return $this; } public function withKeys(array $keys) { $this->keys = $keys; return $this; } /** * Filter results by read/unread status. Note that `true` means to return * only unread notifications, while `false` means to return only //read// * notifications. The default is `null`, which returns both. * * @param mixed True or false to filter results by read status. Null to remove * the filter. * @return this * @task config */ public function withUnread($unread) { $this->unread = $unread; return $this; } /* -( Query Execution )---------------------------------------------------- */ protected function loadPage() { $story_table = new PhabricatorFeedStoryData(); $notification_table = new PhabricatorFeedStoryNotification(); $conn = $story_table->establishConnection('r'); $data = queryfx_all( $conn, - 'SELECT story.*, notif.hasViewed FROM %R notif - JOIN %R story ON notif.chronologicalKey = story.chronologicalKey + 'SELECT story.*, notification.hasViewed FROM %R notification + JOIN %R story ON notification.chronologicalKey = story.chronologicalKey %Q - ORDER BY notif.chronologicalKey DESC + ORDER BY notification.chronologicalKey DESC %Q', $notification_table, $story_table, $this->buildWhereClause($conn), $this->buildLimitClause($conn)); $viewed_map = ipull($data, 'hasViewed', 'chronologicalKey'); $stories = PhabricatorFeedStory::loadAllFromRows( $data, $this->getViewer()); foreach ($stories as $key => $story) { $story->setHasViewed($viewed_map[$key]); } return $stories; } protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { $where = parent::buildWhereClauseParts($conn); if ($this->userPHIDs !== null) { $where[] = qsprintf( $conn, - 'notif.userPHID IN (%Ls)', + 'notification.userPHID IN (%Ls)', $this->userPHIDs); } if ($this->unread !== null) { $where[] = qsprintf( $conn, - 'notif.hasViewed = %d', + 'notification.hasViewed = %d', (int)!$this->unread); } if ($this->keys !== null) { $where[] = qsprintf( $conn, - 'notif.chronologicalKey IN (%Ls)', + 'notification.chronologicalKey IN (%Ls)', $this->keys); } return $where; } protected function willFilterPage(array $stories) { foreach ($stories as $key => $story) { if (!$story->isVisibleInNotifications()) { unset($stories[$key]); } } return $stories; } - protected function getResultCursor($item) { - return $item->getChronologicalKey(); + protected function getDefaultOrderVector() { + return array('key'); + } + + public function getBuiltinOrders() { + return array( + 'newest' => array( + 'vector' => array('key'), + 'name' => pht('Creation (Newest First)'), + 'aliases' => array('created'), + ), + 'oldest' => array( + 'vector' => array('-key'), + 'name' => pht('Creation (Oldest First)'), + ), + ); + } + + public function getOrderableColumns() { + return array( + 'key' => array( + 'table' => 'notification', + 'column' => 'chronologicalKey', + 'type' => 'string', + 'unique' => true, + ), + ); + } + + protected function applyExternalCursorConstraintsToQuery( + PhabricatorCursorPagedPolicyAwareQuery $subquery, + $cursor) { + $subquery->withKeys(array($cursor)); + } + + protected function newExternalCursorStringForResult($object) { + return $object->getChronologicalKey(); + } + + protected function newPagingMapFromPartialObject($object) { + return array( + 'key' => $object->getChronologicalKey(), + ); + } + + protected function getPrimaryTableAlias() { + return 'notification'; } public function getQueryApplicationClass() { return 'PhabricatorNotificationsApplication'; } } diff --git a/src/applications/notification/query/PhabricatorNotificationSearchEngine.php b/src/applications/notification/query/PhabricatorNotificationSearchEngine.php index c7e1998333..4b56c5f5a1 100644 --- a/src/applications/notification/query/PhabricatorNotificationSearchEngine.php +++ b/src/applications/notification/query/PhabricatorNotificationSearchEngine.php @@ -1,141 +1,137 @@ setParameter( 'unread', $this->readBoolFromRequest($request, 'unread')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PhabricatorNotificationQuery()) ->withUserPHIDs(array($this->requireViewer()->getPHID())); if ($saved->getParameter('unread')) { $query->withUnread(true); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $unread = $saved->getParameter('unread'); $form->appendChild( id(new AphrontFormCheckboxControl()) ->setLabel(pht('Unread')) ->addCheckbox( 'unread', 1, pht('Show only unread notifications.'), $unread)); } protected function getURI($path) { return '/notification/'.$path; } protected function getBuiltinQueryNames() { $names = array( 'all' => pht('All Notifications'), 'unread' => pht('Unread Notifications'), ); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; case 'unread': return $query->setParameter('unread', true); } return parent::buildSavedQueryFromBuiltin($query_key); } protected function renderResultList( array $notifications, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($notifications, 'PhabricatorFeedStory'); $viewer = $this->requireViewer(); $image = id(new PHUIIconView()) ->setIcon('fa-bell-o'); $button = id(new PHUIButtonView()) ->setTag('a') ->addSigil('workflow') ->setColor(PHUIButtonView::GREY) ->setIcon($image) ->setText(pht('Mark All Read')); switch ($query->getQueryKey()) { case 'unread': $header = pht('Unread Notifications'); $no_data = pht('You have no unread notifications.'); break; default: $header = pht('Notifications'); $no_data = pht('You have no notifications.'); break; } $clear_uri = id(new PhutilURI('/notification/clear/')); if ($notifications) { $builder = id(new PhabricatorNotificationBuilder($notifications)) ->setUser($viewer); $view = $builder->buildView(); $clear_uri->replaceQueryParam( 'chronoKey', head($notifications)->getChronologicalKey()); } else { $view = phutil_tag_div( 'phabricator-notification no-notifications', $no_data); $button->setDisabled(true); } $button->setHref((string)$clear_uri); $view = id(new PHUIBoxView()) ->addPadding(PHUI::PADDING_MEDIUM) ->addClass('phabricator-notification-list') ->appendChild($view); $result = new PhabricatorApplicationSearchResultView(); $result->addAction($button); $result->setContent($view); return $result; } - public function shouldUseOffsetPaging() { - return true; - } - } diff --git a/src/applications/transactions/query/PhabricatorEditEngineQuery.php b/src/applications/transactions/query/PhabricatorEditEngineQuery.php index ffdbd88535..400b62a487 100644 --- a/src/applications/transactions/query/PhabricatorEditEngineQuery.php +++ b/src/applications/transactions/query/PhabricatorEditEngineQuery.php @@ -1,53 +1,49 @@ engineKeys = $keys; return $this; } protected function loadPage() { $engines = PhabricatorEditEngine::getAllEditEngines(); if ($this->engineKeys !== null) { $engines = array_select_keys($engines, $this->engineKeys); } return $engines; } protected function willFilterPage(array $engines) { $viewer = $this->getViewer(); foreach ($engines as $key => $engine) { $app_class = $engine->getEngineApplicationClass(); if ($app_class === null) { continue; } $can_see = PhabricatorApplication::isClassInstalledForViewer( $app_class, $viewer); if (!$can_see) { $this->didRejectResult($engine); unset($engines[$key]); continue; } } return $engines; } public function getQueryApplicationClass() { return 'PhabricatorTransactionsApplication'; } - protected function getResultCursor($object) { - return null; - } - }