Correct a parameter order swap in "diffusion.historyquery" for Mercurial
[phabricator.git] / src / applications / notification / controller / PhabricatorNotificationPanelController.php
blob5991e8db7b80109fbe47ec8659d0c88c3a86f4ce
1 <?php
3 final class PhabricatorNotificationPanelController
4 extends PhabricatorNotificationController {
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $request->getViewer();
9 $unread_count = $viewer->getUnreadNotificationCount();
11 $warning = $this->prunePhantomNotifications($unread_count);
13 $query = id(new PhabricatorNotificationQuery())
14 ->setViewer($viewer)
15 ->withUserPHIDs(array($viewer->getPHID()))
16 ->setLimit(10);
18 $stories = $query->execute();
20 $clear_ui_class = 'phabricator-notification-clear-all';
21 $clear_uri = id(new PhutilURI('/notification/clear/'));
22 if ($stories) {
23 $builder = id(new PhabricatorNotificationBuilder($stories))
24 ->setUser($viewer);
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';
37 $clear_ui = javelin_tag(
38 'a',
39 array(
40 'sigil' => 'workflow',
41 'href' => (string)$clear_uri,
42 'class' => $clear_ui_class,
44 pht('Mark All Read'));
46 $notifications_link = phutil_tag(
47 'a',
48 array(
49 'href' => '/notification/',
51 pht('Notifications'));
53 $connection_status = new PhabricatorNotificationStatusView();
55 $connection_ui = phutil_tag(
56 'div',
57 array(
58 'class' => 'phabricator-notification-footer',
60 $connection_status);
62 $header = phutil_tag(
63 'div',
64 array(
65 'class' => 'phabricator-notification-header',
67 array(
68 $notifications_link,
69 $clear_ui,
70 ));
72 $content = hsprintf(
73 '%s%s%s%s',
74 $header,
75 $warning,
76 $content,
77 $connection_ui);
79 $json = array(
80 'content' => $content,
81 'number' => (int)$unread_count,
84 return id(new AphrontAjaxResponse())->setContent($json);
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.
93 $viewer = $this->getViewer();
95 if (!$unread_count) {
96 return null;
99 $table = new PhabricatorFeedStoryNotification();
100 $conn = $table->establishConnection('r');
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;
112 $map = array();
113 foreach ($rows as $row) {
114 $map[$row['primaryObjectPHID']][] = $row['chronologicalKey'];
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;
125 foreach ($map[$phid] as $chronological_key) {
126 $purge_keys[] = $chronological_key;
130 if (!$purge_keys) {
131 return null;
134 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
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);
145 PhabricatorUserCache::clearCache(
146 PhabricatorUserNotificationCountCacheType::KEY_COUNT,
147 $viewer->getPHID());
149 unset($unguarded);
151 return phutil_tag(
152 'div',
153 array(
154 'class' => 'phabricator-notification phabricator-notification-warning',
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)));