@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
at upstream/main 163 lines 4.2 kB view raw
1<?php 2 3final class PhabricatorNotificationPanelController 4 extends PhabricatorNotificationController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $viewer = $request->getViewer(); 8 9 $unread_count = $viewer->getUnreadNotificationCount(); 10 11 $warning = $this->prunePhantomNotifications($unread_count); 12 13 $query = id(new PhabricatorNotificationQuery()) 14 ->setViewer($viewer) 15 ->withUserPHIDs(array($viewer->getPHID())) 16 ->setLimit(10); 17 18 $stories = $query->execute(); 19 20 $clear_ui_class = 'phabricator-notification-clear-all'; 21 $clear_uri = new PhutilURI('/notification/clear/'); 22 if ($stories) { 23 $builder = id(new PhabricatorNotificationBuilder($stories)) 24 ->setUser($viewer); 25 26 $notifications_view = $builder->buildView(); 27 $content = $notifications_view->render(); 28 $clear_uri->replaceQueryParam( 29 'chronoKey', 30 head($stories)->getChronologicalKey()); 31 } else { 32 $content = phutil_tag_div( 33 'phabricator-notification no-notifications', 34 pht('You have no notifications.')); 35 $clear_ui_class .= ' disabled'; 36 } 37 $clear_ui = javelin_tag( 38 'a', 39 array( 40 'sigil' => 'workflow', 41 'href' => (string)$clear_uri, 42 'class' => $clear_ui_class, 43 ), 44 pht('Mark All Read')); 45 46 $notifications_link = phutil_tag( 47 'a', 48 array( 49 'href' => '/notification/', 50 ), 51 pht('Notifications')); 52 53 $connection_status = new PhabricatorNotificationStatusView(); 54 55 $connection_ui = phutil_tag( 56 'div', 57 array( 58 'class' => 'phabricator-notification-footer', 59 ), 60 $connection_status); 61 62 $header = phutil_tag( 63 'div', 64 array( 65 'class' => 'phabricator-notification-header', 66 ), 67 array( 68 $notifications_link, 69 $clear_ui, 70 )); 71 72 $content = hsprintf( 73 '%s%s%s%s', 74 $header, 75 $warning, 76 $content, 77 $connection_ui); 78 79 $json = array( 80 'content' => $content, 81 'number' => (int)$unread_count, 82 ); 83 84 return id(new AphrontAjaxResponse())->setContent($json); 85 } 86 87 private function prunePhantomNotifications($unread_count) { 88 // See T8953. If you have an unread notification about an object you 89 // do not have permission to view, it isn't possible to clear it by 90 // visiting the object. Identify these notifications and mark them as 91 // read. 92 93 $viewer = $this->getViewer(); 94 95 if (!$unread_count) { 96 return null; 97 } 98 99 $table = new PhabricatorFeedStoryNotification(); 100 $conn = $table->establishConnection('r'); 101 102 $rows = queryfx_all( 103 $conn, 104 'SELECT chronologicalKey, primaryObjectPHID FROM %T 105 WHERE userPHID = %s AND hasViewed = 0', 106 $table->getTableName(), 107 $viewer->getPHID()); 108 if (!$rows) { 109 return null; 110 } 111 112 $map = array(); 113 foreach ($rows as $row) { 114 $map[$row['primaryObjectPHID']][] = $row['chronologicalKey']; 115 } 116 117 $handles = $viewer->loadHandles(array_keys($map)); 118 $purge_keys = array(); 119 foreach ($handles as $handle) { 120 $phid = $handle->getPHID(); 121 if ($handle->isComplete()) { 122 continue; 123 } 124 125 foreach ($map[$phid] as $chronological_key) { 126 $purge_keys[] = $chronological_key; 127 } 128 } 129 130 if (!$purge_keys) { 131 return null; 132 } 133 134 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 135 136 $conn = $table->establishConnection('w'); 137 queryfx( 138 $conn, 139 'UPDATE %T SET hasViewed = 1 140 WHERE userPHID = %s AND chronologicalKey IN (%Ls)', 141 $table->getTableName(), 142 $viewer->getPHID(), 143 $purge_keys); 144 145 PhabricatorUserCache::clearCache( 146 PhabricatorUserNotificationCountCacheType::KEY_COUNT, 147 $viewer->getPHID()); 148 149 unset($unguarded); 150 151 return phutil_tag( 152 'div', 153 array( 154 'class' => 'phabricator-notification phabricator-notification-warning', 155 ), 156 pht( 157 '%s notification(s) about objects which no longer exist or which '. 158 'you can no longer see were discarded.', 159 phutil_count($purge_keys))); 160 } 161 162 163}