1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-23 21:18:19 +01:00
phorge-phorge/src/applications/notification/query/PhabricatorNotificationSearchEngine.php
epriestley a4a1143b18 Fix an issue where internal paging of notifications could fail if some notifications are not visible
Summary:
Ref T13266. See <https://discourse.phabricator-community.org/t/notification-page-throws-unrecoverable-fatal-error/2651/>.

The "notifications" query currently uses offset paging for no apparent reason (just a legacy issue?), so some of the paging code is only reachable internally.

  - Stop it from using offset paging, since modern cursor paging is fine here (and Feed has used cursor paging for a long time).
  - Fix the non-offset paging to work like Feed.

Also:

  - Remove a couple of stub methods with no callsites after cursor refactoring.

Test Plan:
  - Set things up so I had more than 100 notifications and some in the first 100 were policy filtered, to reproduce the issue (I just made `FeedStory` return `NO_ONE` as a visibility policy).
  - Applied the patch, notifications now page cleanly.
  - Verified that "Next Page" took me to the right place in the result list.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: hskiba

Maniphest Tasks: T13266

Differential Revision: https://secure.phabricator.com/D20455
2019-04-23 11:45:04 -07:00

137 lines
3.4 KiB
PHP

<?php
final class PhabricatorNotificationSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Notifications');
}
public function getApplicationClassName() {
return 'PhabricatorNotificationsApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->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;
}
}