1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Fix an error when users receive notifications about objects they can no longer see

Summary:
Ref T13623. The change in D21577 could lead to a case where we try to access stories the user can't see.

Move the story-loading piece to "willFilterPage()" to make our way thorugh this.

Test Plan:
  - Made FeedStory return nothing to simulate invisible notifications, loaded page.
    - Before: index access fatal.
    - After: clean "no notifications".
  - Loaded notifications normally, saw normal notifications.

Maniphest Tasks: T13623

Differential Revision: https://secure.phabricator.com/D21603
This commit is contained in:
epriestley 2021-03-11 10:31:25 -08:00
parent 4cff4dc68b
commit 0815891e42

View file

@ -63,25 +63,7 @@ final class PhabricatorNotificationQuery
$this->buildWhereClause($conn),
$this->buildLimitClause($conn));
// See T13623. Although most queries for notifications return unique
// 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;
return $data;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
@ -111,14 +93,47 @@ final class PhabricatorNotificationQuery
return $where;
}
protected function willFilterPage(array $stories) {
foreach ($stories as $key => $story) {
if (!$story->isVisibleInNotifications()) {
unset($stories[$key]);
protected function willFilterPage(array $rows) {
// 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()) {
continue;
}
$results[] = $story;
}
return $stories;
return $results;
}
protected function getDefaultOrderVector() {