@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+53 -22
-6
src/applications/meta/query/PhabricatorApplicationQuery.php
··· 170 170 return null; 171 171 } 172 172 173 - protected function getResultCursor($object) { 174 - // TODO: This won't work, but doesn't matter until we write more than 100 175 - // applications. Since we only have about 70, just avoid fataling for now. 176 - return null; 177 - } 178 - 179 173 }
+53 -8
src/applications/notification/query/PhabricatorNotificationQuery.php
··· 53 53 54 54 $data = queryfx_all( 55 55 $conn, 56 - 'SELECT story.*, notif.hasViewed FROM %R notif 57 - JOIN %R story ON notif.chronologicalKey = story.chronologicalKey 56 + 'SELECT story.*, notification.hasViewed FROM %R notification 57 + JOIN %R story ON notification.chronologicalKey = story.chronologicalKey 58 58 %Q 59 - ORDER BY notif.chronologicalKey DESC 59 + ORDER BY notification.chronologicalKey DESC 60 60 %Q', 61 61 $notification_table, 62 62 $story_table, ··· 82 82 if ($this->userPHIDs !== null) { 83 83 $where[] = qsprintf( 84 84 $conn, 85 - 'notif.userPHID IN (%Ls)', 85 + 'notification.userPHID IN (%Ls)', 86 86 $this->userPHIDs); 87 87 } 88 88 89 89 if ($this->unread !== null) { 90 90 $where[] = qsprintf( 91 91 $conn, 92 - 'notif.hasViewed = %d', 92 + 'notification.hasViewed = %d', 93 93 (int)!$this->unread); 94 94 } 95 95 96 96 if ($this->keys !== null) { 97 97 $where[] = qsprintf( 98 98 $conn, 99 - 'notif.chronologicalKey IN (%Ls)', 99 + 'notification.chronologicalKey IN (%Ls)', 100 100 $this->keys); 101 101 } 102 102 ··· 113 113 return $stories; 114 114 } 115 115 116 - protected function getResultCursor($item) { 117 - return $item->getChronologicalKey(); 116 + protected function getDefaultOrderVector() { 117 + return array('key'); 118 + } 119 + 120 + public function getBuiltinOrders() { 121 + return array( 122 + 'newest' => array( 123 + 'vector' => array('key'), 124 + 'name' => pht('Creation (Newest First)'), 125 + 'aliases' => array('created'), 126 + ), 127 + 'oldest' => array( 128 + 'vector' => array('-key'), 129 + 'name' => pht('Creation (Oldest First)'), 130 + ), 131 + ); 132 + } 133 + 134 + public function getOrderableColumns() { 135 + return array( 136 + 'key' => array( 137 + 'table' => 'notification', 138 + 'column' => 'chronologicalKey', 139 + 'type' => 'string', 140 + 'unique' => true, 141 + ), 142 + ); 143 + } 144 + 145 + protected function applyExternalCursorConstraintsToQuery( 146 + PhabricatorCursorPagedPolicyAwareQuery $subquery, 147 + $cursor) { 148 + $subquery->withKeys(array($cursor)); 149 + } 150 + 151 + protected function newExternalCursorStringForResult($object) { 152 + return $object->getChronologicalKey(); 153 + } 154 + 155 + protected function newPagingMapFromPartialObject($object) { 156 + return array( 157 + 'key' => $object->getChronologicalKey(), 158 + ); 159 + } 160 + 161 + protected function getPrimaryTableAlias() { 162 + return 'notification'; 118 163 } 119 164 120 165 public function getQueryApplicationClass() {
-4
src/applications/notification/query/PhabricatorNotificationSearchEngine.php
··· 134 134 return $result; 135 135 } 136 136 137 - public function shouldUseOffsetPaging() { 138 - return true; 139 - } 140 - 141 137 }
-4
src/applications/transactions/query/PhabricatorEditEngineQuery.php
··· 46 46 return 'PhabricatorTransactionsApplication'; 47 47 } 48 48 49 - protected function getResultCursor($object) { 50 - return null; 51 - } 52 - 53 49 }