Changeset View
Changeset View
Standalone View
Standalone View
src/applications/notification/query/PhabricatorNotificationQuery.php
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | $data = queryfx_all( | ||||
%Q | %Q | ||||
ORDER BY notification.chronologicalKey DESC | ORDER BY notification.chronologicalKey DESC | ||||
%Q', | %Q', | ||||
$notification_table, | $notification_table, | ||||
$story_table, | $story_table, | ||||
$this->buildWhereClause($conn), | $this->buildWhereClause($conn), | ||||
$this->buildLimitClause($conn)); | $this->buildLimitClause($conn)); | ||||
// See T13623. Although most queries for notifications return unique | return $data; | ||||
// stories, this isn't a guarantee. | |||||
$story_map = ipull($data, null, 'chronologicalKey'); | |||||
$stories = PhabricatorFeedStory::loadAllFromRows( | |||||
$story_map, | |||||
$this->getViewer()); | |||||
$stories = mpull($stories, null, 'getChronologicalKey'); | |||||
$results = array(); | |||||
foreach ($data as $row) { | |||||
$story_key = $row['chronologicalKey']; | |||||
$has_viewed = $row['hasViewed']; | |||||
$results[] = id(clone $stories[$story_key]) | |||||
->setHasViewed($has_viewed); | |||||
} | |||||
return $results; | |||||
} | } | ||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { | protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { | ||||
$where = parent::buildWhereClauseParts($conn); | $where = parent::buildWhereClauseParts($conn); | ||||
if ($this->userPHIDs !== null) { | if ($this->userPHIDs !== null) { | ||||
$where[] = qsprintf( | $where[] = qsprintf( | ||||
$conn, | $conn, | ||||
Show All 13 Lines | if ($this->keys !== null) { | ||||
$conn, | $conn, | ||||
'notification.chronologicalKey IN (%Ls)', | 'notification.chronologicalKey IN (%Ls)', | ||||
$this->keys); | $this->keys); | ||||
} | } | ||||
return $where; | return $where; | ||||
} | } | ||||
protected function willFilterPage(array $stories) { | protected function willFilterPage(array $rows) { | ||||
foreach ($stories as $key => $story) { | // See T13623. The policy model here is outdated and awkward. | ||||
// Users may have notifications about objects they can no longer see. | |||||
// Two ways this can arise: destroy an object; or change an object's | |||||
// view policy to exclude a user. | |||||
// "PhabricatorFeedStory::loadAllFromRows()" does its own policy filtering. | |||||
// This doesn't align well with modern query sequencing, but we should be | |||||
// able to get away with it by loading here. | |||||
// See T13623. Although most queries for notifications return unique | |||||
// stories, this isn't a guarantee. | |||||
$story_map = ipull($rows, null, 'chronologicalKey'); | |||||
$viewer = $this->getViewer(); | |||||
$stories = PhabricatorFeedStory::loadAllFromRows($story_map, $viewer); | |||||
$stories = mpull($stories, null, 'getChronologicalKey'); | |||||
$results = array(); | |||||
foreach ($rows as $row) { | |||||
$story_key = $row['chronologicalKey']; | |||||
$has_viewed = $row['hasViewed']; | |||||
if (!isset($stories[$story_key])) { | |||||
// NOTE: We can't call "didRejectResult()" here because we don't have | |||||
// a policy object to pass. | |||||
continue; | |||||
} | |||||
$story = id(clone $stories[$story_key]) | |||||
->setHasViewed($has_viewed); | |||||
if (!$story->isVisibleInNotifications()) { | if (!$story->isVisibleInNotifications()) { | ||||
unset($stories[$key]); | continue; | ||||
} | } | ||||
$results[] = $story; | |||||
} | } | ||||
return $stories; | return $results; | ||||
} | } | ||||
protected function getDefaultOrderVector() { | protected function getDefaultOrderVector() { | ||||
return array('key'); | return array('key'); | ||||
} | } | ||||
public function getBuiltinOrders() { | public function getBuiltinOrders() { | ||||
return array( | return array( | ||||
▲ Show 20 Lines • Show All 52 Lines • Show Last 20 Lines |