public function processRequest()
 {
     $request = $this->getRequest();
     $chrono_key = $request->getStr('chronoKey');
     $user = $request->getUser();
     if ($request->isDialogFormPost()) {
         $table = new PhabricatorFeedStoryNotification();
         queryfx($table->establishConnection('w'), 'UPDATE %T SET hasViewed = 1 ' . 'WHERE userPHID = %s AND hasViewed = 0 and chronologicalKey <= %s', $table->getTableName(), $user->getPHID(), $chrono_key);
         return id(new AphrontReloadResponse())->setURI('/notification/');
     }
     $dialog = new AphrontDialogView();
     $dialog->setUser($user);
     $dialog->addCancelButton('/notification/');
     if ($chrono_key) {
         $dialog->setTitle(pht('Really mark all notifications as read?'));
         $dialog->addHiddenInput('chronoKey', $chrono_key);
         $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
         if ($is_serious) {
             $dialog->appendChild(pht('All unread notifications will be marked as read. You can not ' . 'undo this action.'));
         } else {
             $dialog->appendChild(pht("You can't ignore your problems forever, you know."));
         }
         $dialog->addSubmitButton(pht('Mark All Read'));
     } else {
         $dialog->setTitle(pht('No notifications to mark as read.'));
         $dialog->appendChild(pht('You have no unread notifications.'));
     }
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 protected function collectGarbage()
 {
     $table = new PhabricatorFeedStoryNotification();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE chronologicalKey < (%d << 32)
     ORDER BY chronologicalKey ASC LIMIT 100', $table->getTableName(), $this->getGarbageEpoch());
     return $conn_w->getAffectedRows() == 100;
 }
 public static function updateObjectNotificationViews(PhabricatorUser $user, $object_phid)
 {
     if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $notification_table = new PhabricatorFeedStoryNotification();
         $conn = $notification_table->establishConnection('w');
         queryfx($conn, "UPDATE %T\n         SET hasViewed = 1\n         WHERE userPHID = %s\n           AND primaryObjectPHID = %s\n           AND hasViewed = 0", $notification_table->getTableName(), $user->getPHID(), $object_phid);
         unset($unguarded);
     }
 }
 public function newValueForUsers($key, array $users)
 {
     if (!$users) {
         return array();
     }
     $user_phids = mpull($users, 'getPHID');
     $table = new PhabricatorFeedStoryNotification();
     $conn_r = $table->establishConnection('r');
     $rows = queryfx_all($conn_r, 'SELECT userPHID, COUNT(*) N FROM %T
     WHERE userPHID IN (%Ls) AND hasViewed = 0
     GROUP BY userPHID', $table->getTableName(), $user_phids);
     $empty = array_fill_keys($user_phids, 0);
     return ipull($rows, 'N', 'userPHID') + $empty;
 }
 protected function loadPage()
 {
     $story_table = new PhabricatorFeedStoryData();
     $notification_table = new PhabricatorFeedStoryNotification();
     $conn = $story_table->establishConnection('r');
     $data = queryfx_all($conn, 'SELECT story.*, notif.hasViewed FROM %T notif
      JOIN %T story ON notif.chronologicalKey = story.chronologicalKey
      %Q
      ORDER BY notif.chronologicalKey DESC
      %Q', $notification_table->getTableName(), $story_table->getTableName(), $this->buildWhereClause($conn), $this->buildLimitClause($conn));
     $viewed_map = ipull($data, 'hasViewed', 'chronologicalKey');
     $stories = PhabricatorFeedStory::loadAllFromRows($data, $this->getViewer());
     foreach ($stories as $key => $story) {
         $story->setHasViewed($viewed_map[$key]);
     }
     return $stories;
 }
 public function execute()
 {
     if (!$this->userPHID) {
         throw new Exception("Call setUser() before executing the query");
     }
     $story_table = new PhabricatorFeedStoryData();
     $notification_table = new PhabricatorFeedStoryNotification();
     $conn = $story_table->establishConnection('r');
     $data = queryfx_all($conn, "SELECT story.*, notif.primaryObjectPHID, notif.hasViewed FROM %T notif\n         JOIN %T story ON notif.chronologicalKey = story.chronologicalKey\n         %Q\n         ORDER BY notif.chronologicalKey DESC\n         %Q", $notification_table->getTableName(), $story_table->getTableName(), $this->buildWhereClause($conn), $this->buildLimitClause($conn));
     $viewed_map = ipull($data, 'hasViewed', 'chronologicalKey');
     $primary_map = ipull($data, 'primaryObjectPHID', 'chronologicalKey');
     $stories = PhabricatorFeedStory::loadAllFromRows($data);
     foreach ($stories as $key => $story) {
         $story->setHasViewed($viewed_map[$key]);
         $story->setPrimaryObjectPHID($primary_map[$key]);
     }
     return $stories;
 }
 public static function updateObjectNotificationViews(PhabricatorUser $user, $object_phid)
 {
     if (PhabricatorEnv::isReadOnly()) {
         return;
     }
     $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
     $notification_table = new PhabricatorFeedStoryNotification();
     $conn = $notification_table->establishConnection('w');
     queryfx($conn, 'UPDATE %T
    SET hasViewed = 1
    WHERE userPHID = %s
      AND primaryObjectPHID = %s
      AND hasViewed = 0', $notification_table->getTableName(), $user->getPHID(), $object_phid);
     unset($unguarded);
     $count_key = PhabricatorUserNotificationCountCacheType::KEY_COUNT;
     PhabricatorUserCache::clearCache($count_key, $user->getPHID());
     $user->clearCacheData($count_key);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($request->isDialogFormPost()) {
         $table = new PhabricatorFeedStoryNotification();
         queryfx($table->establishConnection('w'), 'UPDATE %T SET hasViewed = 1 WHERE
       userPHID = %s AND hasViewed = 0', $table->getTableName(), $user->getPHID());
         return id(new AphrontReloadResponse())->setURI('/notification/');
     }
     $dialog = new AphrontDialogView();
     $dialog->setUser($user);
     $dialog->setTitle('Really mark all notifications as read?');
     $dialog->appendChild("You can't ignore your problems forever, you know.");
     $dialog->addCancelButton('/notification/');
     $dialog->addSubmitButton('Mark All Read');
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 public function produceAphrontResponse()
 {
     $controller = $this->getController();
     if (!$this->getApplicationMenu()) {
         $application_menu = $controller->buildApplicationMenu();
         if ($application_menu) {
             $this->setApplicationMenu($application_menu);
         }
     }
     $viewer = $this->getUser();
     if ($viewer && $viewer->getPHID()) {
         $object_phids = $this->pageObjects;
         foreach ($object_phids as $object_phid) {
             PhabricatorFeedStoryNotification::updateObjectNotificationViews($viewer, $object_phid);
         }
     }
     if ($this->getRequest()->isQuicksand()) {
         $content = $this->renderForQuicksand();
         $response = id(new AphrontAjaxResponse())->setContent($content);
     } else {
         $content = $this->render();
         $response = id(new AphrontWebpageResponse())->setContent($content);
     }
     return $response;
 }
 public function buildApplicationPage($view, array $options)
 {
     $page = $this->buildStandardPageView();
     $title = PhabricatorEnv::getEnvConfig('phabricator.serious-business') ? 'Phabricator' : pht('Bacon Ice Cream for Breakfast');
     $application = $this->getCurrentApplication();
     $page->setTitle(idx($options, 'title', $title));
     if ($application) {
         $page->setApplicationName($application->getName());
         if ($application->getTitleGlyph()) {
             $page->setGlyph($application->getTitleGlyph());
         }
     }
     if (idx($options, 'class')) {
         $page->addClass($options['class']);
     }
     if (!$view instanceof AphrontSideNavFilterView) {
         $nav = new AphrontSideNavFilterView();
         $nav->appendChild($view);
         $view = $nav;
     }
     $user = $this->getRequest()->getUser();
     $view->setUser($user);
     $page->appendChild($view);
     $object_phids = idx($options, 'pageObjects', array());
     if ($object_phids) {
         $page->appendPageObjects($object_phids);
         foreach ($object_phids as $object_phid) {
             PhabricatorFeedStoryNotification::updateObjectNotificationViews($user, $object_phid);
         }
     }
     if (idx($options, 'device', true)) {
         $page->setDeviceReady(true);
     }
     $page->setShowFooter(idx($options, 'showFooter', true));
     $page->setShowChrome(idx($options, 'chrome', true));
     $application_menu = $this->buildApplicationMenu();
     if ($application_menu) {
         $page->setApplicationMenu($application_menu);
     }
     return $this->buildPageResponse($page);
 }
 private function destroyNotifications($object_phid)
 {
     $table = new PhabricatorFeedStoryNotification();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE primaryObjectPHID = %s', $table->getTableName(), $object_phid);
 }
 private function insertNotifications($chrono_key, array $subscribed_phids)
 {
     if (!$this->primaryObjectPHID) {
         throw new Exception(pht('You must call %s if you %s!', 'setPrimaryObjectPHID()', 'setSubscribedPHIDs()'));
     }
     $notif = new PhabricatorFeedStoryNotification();
     $sql = array();
     $conn = $notif->establishConnection('w');
     $will_receive_mail = array_fill_keys($this->mailRecipientPHIDs, true);
     foreach (array_unique($subscribed_phids) as $user_phid) {
         if (isset($will_receive_mail[$user_phid])) {
             $mark_read = 1;
         } else {
             $mark_read = 0;
         }
         $sql[] = qsprintf($conn, '(%s, %s, %s, %d)', $this->primaryObjectPHID, $user_phid, $chrono_key, $mark_read);
     }
     if ($sql) {
         queryfx($conn, 'INSERT INTO %T ' . '(primaryObjectPHID, userPHID, chronologicalKey, hasViewed) ' . 'VALUES %Q', $notif->getTableName(), implode(', ', $sql));
     }
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $viewer_is_anonymous = !$user->isLoggedIn();
     $revision = id(new DifferentialRevision())->load($this->revisionID);
     if (!$revision) {
         return new Aphront404Response();
     }
     $revision->loadRelationships();
     $diffs = $revision->loadDiffs();
     if (!$diffs) {
         throw new Exception("This revision has no diffs. Something has gone quite wrong.");
     }
     $diff_vs = $request->getInt('vs');
     $target_id = $request->getInt('id');
     $target = idx($diffs, $target_id, end($diffs));
     $target_manual = $target;
     if (!$target_id) {
         foreach ($diffs as $diff) {
             if ($diff->getCreationMethod() != 'commit') {
                 $target_manual = $diff;
             }
         }
     }
     if (empty($diffs[$diff_vs])) {
         $diff_vs = null;
     }
     $arc_project = $target->loadArcanistProject();
     $repository = $arc_project ? $arc_project->loadRepository() : null;
     list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository);
     if ($request->getExists('download')) {
         return $this->buildRawDiffResponse($changesets, $vs_changesets, $vs_map, $repository);
     }
     list($aux_fields, $props) = $this->loadAuxiliaryFieldsAndProperties($revision, $target_manual, array('local:commits', 'arc:lint', 'arc:unit'));
     $comments = $revision->loadComments();
     $comments = array_merge($this->getImplicitComments($revision, reset($diffs)), $comments);
     $all_changesets = $changesets;
     $inlines = $this->loadInlineComments($comments, $all_changesets);
     $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID()), mpull($comments, 'getAuthorPHID'));
     foreach ($comments as $comment) {
         $metadata = $comment->getMetadata();
         $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS);
         if ($added_reviewers) {
             foreach ($added_reviewers as $phid) {
                 $object_phids[] = $phid;
             }
         }
         $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS);
         if ($added_ccs) {
             foreach ($added_ccs as $phid) {
                 $object_phids[] = $phid;
             }
         }
     }
     foreach ($revision->getAttached() as $type => $phids) {
         foreach ($phids as $phid => $info) {
             $object_phids[] = $phid;
         }
     }
     $aux_phids = array();
     foreach ($aux_fields as $key => $aux_field) {
         $aux_phids[$key] = $aux_field->getRequiredHandlePHIDsForRevisionView();
     }
     $object_phids = array_merge($object_phids, array_mergev($aux_phids));
     $object_phids = array_unique($object_phids);
     $handles = id(new PhabricatorObjectHandleData($object_phids))->loadHandles();
     foreach ($aux_fields as $key => $aux_field) {
         // Make sure each field only has access to handles it specifically
         // requested, not all handles. Otherwise you can get a field which works
         // only in the presence of other fields.
         $aux_field->setHandles(array_select_keys($handles, $aux_phids[$key]));
     }
     $reviewer_warning = null;
     $has_live_reviewer = false;
     foreach ($revision->getReviewers() as $reviewer) {
         if (!$handles[$reviewer]->isDisabled()) {
             $has_live_reviewer = true;
         }
     }
     if (!$has_live_reviewer) {
         $reviewer_warning = new AphrontErrorView();
         $reviewer_warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
         $reviewer_warning->setTitle('No Active Reviewers');
         if ($revision->getReviewers()) {
             $reviewer_warning->appendChild('<p>All specified reviewers are disabled. You may want to add ' . 'some new reviewers.</p>');
         } else {
             $reviewer_warning->appendChild('<p>This revision has no specified reviewers. You may want to ' . 'add some.</p>');
         }
     }
     $request_uri = $request->getRequestURI();
     $limit = 100;
     $large = $request->getStr('large');
     if (count($changesets) > $limit && !$large) {
         $count = number_format(count($changesets));
         $warning = new AphrontErrorView();
         $warning->setTitle('Very Large Diff');
         $warning->setSeverity(AphrontErrorView::SEVERITY_WARNING);
         $warning->setWidth(AphrontErrorView::WIDTH_WIDE);
         $warning->appendChild("<p>This diff is very large and affects {$count} files. Load " . "each file individually. " . "<strong>" . phutil_render_tag('a', array('href' => $request_uri->alter('large', 'true')->setFragment('toc')), 'Show All Files Inline') . "</strong>");
         $warning = $warning->render();
         $my_inlines = id(new DifferentialInlineComment())->loadAllWhere('revisionID = %d AND commentID IS NULL AND authorPHID = %s AND ' . 'changesetID IN (%Ld)', $this->revisionID, $user->getPHID(), mpull($changesets, 'getID'));
         $visible_changesets = array();
         foreach ($inlines + $my_inlines as $inline) {
             $changeset_id = $inline->getChangesetID();
             if (isset($changesets[$changeset_id])) {
                 $visible_changesets[$changeset_id] = $changesets[$changeset_id];
             }
         }
         if (!empty($props['arc:lint'])) {
             $changeset_paths = mpull($changesets, null, 'getFilename');
             foreach ($props['arc:lint'] as $lint) {
                 $changeset = idx($changeset_paths, $lint['path']);
                 if ($changeset) {
                     $visible_changesets[$changeset->getID()] = $changeset;
                 }
             }
         }
     } else {
         $warning = null;
         $visible_changesets = $changesets;
     }
     $revision_detail = new DifferentialRevisionDetailView();
     $revision_detail->setRevision($revision);
     $revision_detail->setAuxiliaryFields($aux_fields);
     $actions = $this->getRevisionActions($revision);
     $custom_renderer_class = PhabricatorEnv::getEnvConfig('differential.revision-custom-detail-renderer');
     if ($custom_renderer_class) {
         // TODO: build a better version of the action links and deprecate the
         // whole DifferentialRevisionDetailRenderer class.
         $custom_renderer = newv($custom_renderer_class, array());
         $custom_renderer->setDiff($target);
         if ($diff_vs) {
             $custom_renderer->setVSDiff($diffs[$diff_vs]);
         }
         $actions = array_merge($actions, $custom_renderer->generateActionLinks($revision, $target_manual));
     }
     $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_ALL);
     if ($arc_project) {
         list($symbol_indexes, $project_phids) = $this->buildSymbolIndexes($arc_project, $visible_changesets);
     } else {
         $symbol_indexes = array();
         $project_phids = null;
     }
     $revision_detail->setActions($actions);
     $revision_detail->setUser($user);
     $comment_view = new DifferentialRevisionCommentListView();
     $comment_view->setComments($comments);
     $comment_view->setHandles($handles);
     $comment_view->setInlineComments($inlines);
     $comment_view->setChangesets($all_changesets);
     $comment_view->setUser($user);
     $comment_view->setTargetDiff($target);
     $comment_view->setVersusDiffID($diff_vs);
     if ($arc_project) {
         Javelin::initBehavior('repository-crossreference', array('section' => $comment_view->getID(), 'projects' => $project_phids));
     }
     $changeset_view = new DifferentialChangesetListView();
     $changeset_view->setChangesets($changesets);
     $changeset_view->setVisibleChangesets($visible_changesets);
     if (!$viewer_is_anonymous) {
         $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/');
     }
     $changeset_view->setStandaloneURI('/differential/changeset/');
     $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new');
     $changeset_view->setUser($user);
     $changeset_view->setDiff($target);
     $changeset_view->setRenderingReferences($rendering_references);
     $changeset_view->setVsMap($vs_map);
     $changeset_view->setWhitespace($whitespace);
     if ($repository) {
         $changeset_view->setRepository($repository);
     }
     $changeset_view->setSymbolIndexes($symbol_indexes);
     $diff_history = new DifferentialRevisionUpdateHistoryView();
     $diff_history->setDiffs($diffs);
     $diff_history->setSelectedVersusDiffID($diff_vs);
     $diff_history->setSelectedDiffID($target->getID());
     $diff_history->setSelectedWhitespace($whitespace);
     $diff_history->setUser($user);
     $local_view = new DifferentialLocalCommitsView();
     $local_view->setUser($user);
     $local_view->setLocalCommits(idx($props, 'local:commits'));
     if ($repository) {
         $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository);
     } else {
         $other_revisions = array();
     }
     $other_view = null;
     if ($other_revisions) {
         $other_view = $this->renderOtherRevisions($other_revisions);
     }
     $toc_view = new DifferentialDiffTableOfContentsView();
     $toc_view->setChangesets($changesets);
     $toc_view->setVisibleChangesets($visible_changesets);
     $toc_view->setRenderingReferences($rendering_references);
     $toc_view->setUnitTestData(idx($props, 'arc:unit', array()));
     if ($repository) {
         $toc_view->setRepository($repository);
     }
     $toc_view->setDiff($target);
     $toc_view->setUser($user);
     $toc_view->setRevisionID($revision->getID());
     $toc_view->setWhitespace($whitespace);
     $comment_form = null;
     if (!$viewer_is_anonymous) {
         $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID());
         if ($draft) {
             $draft = $draft->getDraft();
         } else {
             $draft = null;
         }
         $comment_form = new DifferentialAddCommentView();
         $comment_form->setRevision($revision);
         $comment_form->setAuxFields($aux_fields);
         $comment_form->setActions($this->getRevisionCommentActions($revision));
         $comment_form->setActionURI('/differential/comment/save/');
         $comment_form->setUser($user);
         $comment_form->setDraft($draft);
     }
     $pane_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id));
     Javelin::initBehavior('differential-user-select');
     $page_pane = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets($changesets)->setID($pane_id)->appendChild($comment_view->render() . $diff_history->render() . $warning . $local_view->render() . $toc_view->render() . $other_view . $changeset_view->render());
     if ($comment_form) {
         $page_pane->appendChild($comment_form->render());
     }
     PhabricatorFeedStoryNotification::updateObjectNotificationViews($user, $revision->getPHID());
     $top_anchor = id(new PhabricatorAnchorView())->setAnchorName('top')->setNavigationMarker(true);
     $nav = $this->buildSideNavView($revision, $changesets);
     $nav->selectFilter('');
     $nav->appendChild(array($reviewer_warning, $top_anchor, $revision_detail, $page_pane));
     return $this->buildApplicationPage($nav, array('title' => 'D' . $revision->getID() . ' ' . $revision->getTitle()));
 }
 private function insertNotifications($chrono_key)
 {
     if (!$this->subscribedPHIDs) {
         return;
     }
     if (!$this->primaryObjectPHID) {
         throw new Exception("You must call setPrimaryObjectPHID() if you setSubscribedPHIDs()!");
     }
     $notif = new PhabricatorFeedStoryNotification();
     $sql = array();
     $conn = $notif->establishConnection('w');
     foreach (array_unique($this->subscribedPHIDs) as $user_phid) {
         $sql[] = qsprintf($conn, '(%s, %s, %s, %d)', $this->primaryObjectPHID, $user_phid, $chrono_key, 0);
     }
     queryfx($conn, 'INSERT INTO %T
  (primaryObjectPHID, userPHID, chronologicalKey, hasViewed)
  VALUES %Q', $notif->getTableName(), implode(', ', $sql));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $e_title = null;
     $priority_map = ManiphestTaskPriority::getTaskPriorityMap();
     $task = id(new ManiphestTask())->load($this->id);
     if (!$task) {
         return new Aphront404Response();
     }
     $workflow = $request->getStr('workflow');
     $parent_task = null;
     if ($workflow && is_numeric($workflow)) {
         $parent_task = id(new ManiphestTask())->load($workflow);
     }
     $transactions = id(new ManiphestTransaction())->loadAllWhere('taskID = %d ORDER BY id ASC', $task->getID());
     $e_commit = PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT;
     $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK;
     $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK;
     $e_rev = PhabricatorEdgeConfig::TYPE_TASK_HAS_RELATED_DREV;
     $phid = $task->getPHID();
     $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev));
     $edges = $query->execute();
     $commit_phids = array_keys($edges[$phid][$e_commit]);
     $dep_on_tasks = array_keys($edges[$phid][$e_dep_on]);
     $dep_by_tasks = array_keys($edges[$phid][$e_dep_by]);
     $revs = array_keys($edges[$phid][$e_rev]);
     $phids = array_fill_keys($query->getDestinationPHIDs(), true);
     foreach ($transactions as $transaction) {
         foreach ($transaction->extractPHIDs() as $phid) {
             $phids[$phid] = true;
         }
     }
     foreach ($task->getCCPHIDs() as $phid) {
         $phids[$phid] = true;
     }
     foreach ($task->getProjectPHIDs() as $phid) {
         $phids[$phid] = true;
     }
     if ($task->getOwnerPHID()) {
         $phids[$task->getOwnerPHID()] = true;
     }
     $phids[$task->getAuthorPHID()] = true;
     $attached = $task->getAttached();
     foreach ($attached as $type => $list) {
         foreach ($list as $phid => $info) {
             $phids[$phid] = true;
         }
     }
     if ($parent_task) {
         $phids[$parent_task->getPHID()] = true;
     }
     $phids = array_keys($phids);
     $handles = $this->loadViewerHandles($phids);
     $dict = array();
     $dict['Status'] = '<strong>' . ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()) . '</strong>';
     $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : '<em>None</em>';
     $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName($task->getPriority());
     $cc = $task->getCCPHIDs();
     if ($cc) {
         $cc_links = array();
         foreach ($cc as $phid) {
             $cc_links[] = $handles[$phid]->renderLink();
         }
         $dict['CC'] = implode(', ', $cc_links);
     } else {
         $dict['CC'] = '<em>None</em>';
     }
     $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink();
     $source = $task->getOriginalEmailSource();
     if ($source) {
         $subject = '[T' . $task->getID() . '] ' . $task->getTitle();
         $dict['From Email'] = phutil_render_tag('a', array('href' => 'mailto:' . $source . '?subject=' . $subject), phutil_escape_html($source));
     }
     $projects = $task->getProjectPHIDs();
     if ($projects) {
         $project_links = array();
         foreach ($projects as $phid) {
             $project_links[] = $handles[$phid]->renderLink();
         }
         $dict['Projects'] = implode(', ', $project_links);
     } else {
         $dict['Projects'] = '<em>None</em>';
     }
     $extensions = ManiphestTaskExtensions::newExtensions();
     $aux_fields = $extensions->getAuxiliaryFieldSpecifications();
     if ($aux_fields) {
         $task->loadAndAttachAuxiliaryAttributes();
         foreach ($aux_fields as $aux_field) {
             $aux_key = $aux_field->getAuxiliaryKey();
             $aux_field->setValue($task->getAuxiliaryAttribute($aux_key));
             $value = $aux_field->renderForDetailView();
             if (strlen($value)) {
                 $dict[$aux_field->getLabel()] = $value;
             }
         }
     }
     if ($dep_by_tasks) {
         $dict['Dependent Tasks'] = $this->renderHandleList(array_select_keys($handles, $dep_by_tasks));
     }
     if ($dep_on_tasks) {
         $dict['Depends On'] = $this->renderHandleList(array_select_keys($handles, $dep_on_tasks));
     }
     if ($revs) {
         $dict['Revisions'] = $this->renderHandleList(array_select_keys($handles, $revs));
     }
     if ($commit_phids) {
         $dict['Commits'] = $this->renderHandleList(array_select_keys($handles, $commit_phids));
     }
     $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE);
     if ($file_infos) {
         $file_phids = array_keys($file_infos);
         $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids);
         $views = array();
         foreach ($files as $file) {
             $view = new AphrontFilePreviewView();
             $view->setFile($file);
             $views[] = $view->render();
         }
         $dict['Files'] = implode('', $views);
     }
     $context_bar = null;
     if ($parent_task) {
         $context_bar = new AphrontContextBarView();
         $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?parent=' . $parent_task->getID(), 'class' => 'green button'), 'Create Another Subtask'));
         $context_bar->appendChild('Created a subtask of <strong>' . $handles[$parent_task->getPHID()]->renderLink() . '</strong>');
     } else {
         if ($workflow == 'create') {
             $context_bar = new AphrontContextBarView();
             $context_bar->addButton('<label>Create Another:</label>');
             $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/?template=' . $task->getID(), 'class' => 'green button'), 'Similar Task'));
             $context_bar->addButton(phutil_render_tag('a', array('href' => '/maniphest/task/create/', 'class' => 'green button'), 'Empty Task'));
             $context_bar->appendChild('New task created.');
         }
     }
     $actions = array();
     $action = new AphrontHeadsupActionView();
     $action->setName('Edit Task');
     $action->setURI('/maniphest/task/edit/' . $task->getID() . '/');
     $action->setClass('action-edit');
     $actions[] = $action;
     require_celerity_resource('phabricator-flag-css');
     $flag = PhabricatorFlagQuery::loadUserFlag($user, $task->getPHID());
     if ($flag) {
         $class = PhabricatorFlagColor::getCSSClass($flag->getColor());
         $color = PhabricatorFlagColor::getColorName($flag->getColor());
         $action = new AphrontHeadsupActionView();
         $action->setClass('flag-clear ' . $class);
         $action->setURI('/flag/delete/' . $flag->getID() . '/');
         $action->setName('Remove ' . $color . ' Flag');
         $action->setWorkflow(true);
         $actions[] = $action;
     } else {
         $action = new AphrontHeadsupActionView();
         $action->setClass('phabricator-flag-ghost');
         $action->setURI('/flag/edit/' . $task->getPHID() . '/');
         $action->setName('Flag Task');
         $action->setWorkflow(true);
         $actions[] = $action;
     }
     require_celerity_resource('phabricator-object-selector-css');
     require_celerity_resource('javelin-behavior-phabricator-object-selector');
     $action = new AphrontHeadsupActionView();
     $action->setName('Merge Duplicates');
     $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/merge/');
     $action->setWorkflow(true);
     $action->setClass('action-merge');
     $actions[] = $action;
     $action = new AphrontHeadsupActionView();
     $action->setName('Create Subtask');
     $action->setURI('/maniphest/task/create/?parent=' . $task->getID());
     $action->setClass('action-branch');
     $actions[] = $action;
     $action = new AphrontHeadsupActionView();
     $action->setName('Edit Dependencies');
     $action->setURI('/search/attach/' . $task->getPHID() . '/TASK/dependencies/');
     $action->setWorkflow(true);
     $action->setClass('action-dependencies');
     $actions[] = $action;
     $action = new AphrontHeadsupActionView();
     $action->setName('Edit Differential Revisions');
     $action->setURI('/search/attach/' . $task->getPHID() . '/DREV/');
     $action->setWorkflow(true);
     $action->setClass('action-attach');
     $actions[] = $action;
     $action_list = new AphrontHeadsupActionListView();
     $action_list->setActions($actions);
     $headsup_panel = new AphrontHeadsupView();
     $headsup_panel->setObjectName('T' . $task->getID());
     $headsup_panel->setHeader($task->getTitle());
     $headsup_panel->setActionList($action_list);
     $headsup_panel->setProperties($dict);
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($user);
     $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION);
     foreach ($transactions as $xaction) {
         if ($xaction->hasComments()) {
             $engine->addObject($xaction, ManiphestTransaction::MARKUP_FIELD_BODY);
         }
     }
     $engine->process();
     $headsup_panel->appendChild('<div class="phabricator-remarkup">' . $engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION) . '</div>');
     $transaction_types = ManiphestTransactionType::getTransactionTypeMap();
     $resolution_types = ManiphestTaskStatus::getTaskStatusMap();
     if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) {
         $resolution_types = array_select_keys($resolution_types, array(ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE));
     } else {
         $resolution_types = array(ManiphestTaskStatus::STATUS_OPEN => 'Reopened');
         $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task';
         unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]);
         unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]);
     }
     $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')');
     $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID());
     if ($draft) {
         $draft_text = $draft->getDraft();
     } else {
         $draft_text = null;
     }
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     if ($is_serious) {
         // Prevent tasks from being closed "out of spite" in serious business
         // installs.
         unset($resolution_types[ManiphestTaskStatus::STATUS_CLOSED_SPITE]);
     }
     $comment_form = new AphrontFormView();
     $comment_form->setUser($user)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Resolution')->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Assign To')->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('CCs')->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormSelectControl())->setLabel('Priority')->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Projects')->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormFileControl())->setLabel('File')->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setLabel('Comments')->setName('comments')->setValue($draft_text)->setID('transaction-comments'))->appendChild(id(new AphrontFormDragAndDropUploadControl())->setLabel('Attached Files')->setName('files')->setActivatedClass('aphront-panel-view-drag-and-drop'))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_serious ? 'Submit' : 'Avast!'));
     $control_map = array(ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file');
     $tokenizer_map = array(ManiphestTransactionType::TYPE_PROJECTS => array('id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a project name...'), ManiphestTransactionType::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user name...'), ManiphestTransactionType::TYPE_CCS => array('id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user or mailing list...'));
     Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map));
     Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map));
     $comment_panel = new AphrontPanelView();
     $comment_panel->appendChild($comment_form);
     $comment_panel->addClass('aphront-panel-accent');
     $comment_panel->setHeader($is_serious ? 'Add Comment' : 'Weigh In');
     $preview_panel = '<div class="aphront-panel-preview">
     <div id="transaction-preview">
       <div class="aphront-panel-preview-loading-text">
         Loading preview...
       </div>
     </div>
   </div>';
     $transaction_view = new ManiphestTransactionListView();
     $transaction_view->setTransactions($transactions);
     $transaction_view->setHandles($handles);
     $transaction_view->setUser($user);
     $transaction_view->setAuxiliaryFields($aux_fields);
     $transaction_view->setMarkupEngine($engine);
     PhabricatorFeedStoryNotification::updateObjectNotificationViews($user, $task->getPHID());
     return $this->buildStandardPageResponse(array($context_bar, $headsup_panel, $transaction_view, $comment_panel, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID())));
 }
 public function destroyObject(PhabricatorDestructionEngine $engine, $object)
 {
     $table = new PhabricatorFeedStoryNotification();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE primaryObjectPHID = %s', $table->getTableName(), $object->getPHID());
 }