Differential D19384 Diff 46374 src/applications/notification/controller/PhabricatorNotificationPanelController.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/notification/controller/PhabricatorNotificationPanelController.php
<?php | <?php | ||||
final class PhabricatorNotificationPanelController | final class PhabricatorNotificationPanelController | ||||
extends PhabricatorNotificationController { | extends PhabricatorNotificationController { | ||||
public function handleRequest(AphrontRequest $request) { | public function handleRequest(AphrontRequest $request) { | ||||
$viewer = $request->getViewer(); | $viewer = $request->getViewer(); | ||||
$unread_count = $viewer->getUnreadNotificationCount(); | |||||
$warning = $this->prunePhantomNotifications($unread_count); | |||||
$query = id(new PhabricatorNotificationQuery()) | $query = id(new PhabricatorNotificationQuery()) | ||||
->setViewer($viewer) | ->setViewer($viewer) | ||||
->withUserPHIDs(array($viewer->getPHID())) | ->withUserPHIDs(array($viewer->getPHID())) | ||||
->setLimit(10); | ->setLimit(10); | ||||
$stories = $query->execute(); | $stories = $query->execute(); | ||||
$clear_ui_class = 'phabricator-notification-clear-all'; | $clear_ui_class = 'phabricator-notification-clear-all'; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | $header = phutil_tag( | ||||
'class' => 'phabricator-notification-header', | 'class' => 'phabricator-notification-header', | ||||
), | ), | ||||
array( | array( | ||||
$notifications_link, | $notifications_link, | ||||
$clear_ui, | $clear_ui, | ||||
)); | )); | ||||
$content = hsprintf( | $content = hsprintf( | ||||
'%s%s%s', | '%s%s%s%s', | ||||
$header, | $header, | ||||
$warning, | |||||
$content, | $content, | ||||
$connection_ui); | $connection_ui); | ||||
$unread_count = $viewer->getUnreadNotificationCount(); | |||||
$json = array( | $json = array( | ||||
'content' => $content, | 'content' => $content, | ||||
'number' => (int)$unread_count, | 'number' => (int)$unread_count, | ||||
); | ); | ||||
return id(new AphrontAjaxResponse())->setContent($json); | return id(new AphrontAjaxResponse())->setContent($json); | ||||
} | } | ||||
private function prunePhantomNotifications($unread_count) { | |||||
// See T8953. If you have an unread notification about an object you | |||||
// do not have permission to view, it isn't possible to clear it by | |||||
// visiting the object. Identify these notifications and mark them as | |||||
// read. | |||||
$viewer = $this->getViewer(); | |||||
if (!$unread_count) { | |||||
return null; | |||||
} | |||||
$table = new PhabricatorFeedStoryNotification(); | |||||
$conn = $table->establishConnection('r'); | |||||
$rows = queryfx_all( | |||||
$conn, | |||||
'SELECT chronologicalKey, primaryObjectPHID FROM %T | |||||
WHERE userPHID = %s AND hasViewed = 0', | |||||
$table->getTableName(), | |||||
$viewer->getPHID()); | |||||
if (!$rows) { | |||||
return null; | |||||
} | |||||
$map = array(); | |||||
foreach ($rows as $row) { | |||||
$map[$row['primaryObjectPHID']][] = $row['chronologicalKey']; | |||||
} | |||||
$handles = $viewer->loadHandles(array_keys($map)); | |||||
$purge_keys = array(); | |||||
foreach ($handles as $handle) { | |||||
$phid = $handle->getPHID(); | |||||
if ($handle->isComplete()) { | |||||
continue; | |||||
} | |||||
foreach ($map[$phid] as $chronological_key) { | |||||
$purge_keys[] = $chronological_key; | |||||
} | |||||
} | |||||
if (!$purge_keys) { | |||||
return null; | |||||
} | |||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | |||||
$conn = $table->establishConnection('w'); | |||||
queryfx( | |||||
$conn, | |||||
'UPDATE %T SET hasViewed = 1 | |||||
WHERE userPHID = %s AND chronologicalKey IN (%Ls)', | |||||
$table->getTableName(), | |||||
$viewer->getPHID(), | |||||
$purge_keys); | |||||
PhabricatorUserCache::clearCache( | |||||
PhabricatorUserNotificationCountCacheType::KEY_COUNT, | |||||
$viewer->getPHID()); | |||||
unset($unguarded); | |||||
return phutil_tag( | |||||
'div', | |||||
array( | |||||
'class' => 'phabricator-notification phabricator-notification-warning', | |||||
), | |||||
pht( | |||||
'%s notification(s) about objects which no longer exist or which '. | |||||
'you can no longer see were discarded.', | |||||
phutil_count($purge_keys))); | |||||
} | |||||
} | } |