protected function getVerb()
 {
     $comment = $this->getComment();
     $action = $comment->getAction();
     $verb = DifferentialAction::getActionPastTenseVerb($action);
     return $verb;
 }
 public function runBackgroundTasks()
 {
     $iterator = new PhabricatorTimelineIterator('ircdiffx', array('difx'));
     if (!$this->skippedOldEvents) {
         // Since we only want to post notifications about new events, skip
         // everything that's happened in the past when we start up so we'll
         // only process real-time events.
         foreach ($iterator as $event) {
             // Ignore all old events.
         }
         $this->skippedOldEvents = true;
         return;
     }
     foreach ($iterator as $event) {
         $data = $event->getData();
         if (!$data) {
             continue;
         }
         $actor_phid = $data['actor_phid'];
         $phids = array($actor_phid);
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $verb = DifferentialAction::getActionPastTenseVerb($data['action']);
         $actor_name = $handles[$actor_phid]->getName();
         $message = "{$actor_name} {$verb} revision D" . $data['revision_id'] . ".";
         foreach ($this->getConfig('notification.channels') as $channel) {
             $this->write('PRIVMSG', "{$channel} :{$message}");
         }
     }
 }
 public function render()
 {
     $viewer = $this->getViewer();
     $this->requireResource('differential-revision-add-comment-css');
     $revision = $this->revision;
     $action = null;
     if ($this->draft) {
         $action = idx($this->draft->getMetadata(), 'action');
     }
     $enable_reviewers = DifferentialAction::allowReviewers($action);
     $enable_ccs = $action == DifferentialAction::ACTION_ADDCCS;
     $add_reviewers_labels = array('add_reviewers' => pht('Add Reviewers'), 'request_review' => pht('Add Reviewers'), 'resign' => pht('Suggest Reviewers'));
     $mailable_source = new PhabricatorMetaMTAMailableDatasource();
     // TODO: This should be a reviewers datasource, but it's a mess.
     $reviewer_source = new PhabricatorMetaMTAMailableDatasource();
     $form = new AphrontFormView();
     $form->setWorkflow(true)->setViewer($viewer)->setAction($this->actionURI)->addHiddenInput('revision_id', $revision->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setValue($action)->setID('comment-action')->setOptions($this->actions))->appendControl(id(new AphrontFormTokenizerControl())->setLabel($enable_reviewers ? $add_reviewers_labels[$action] : $add_reviewers_labels['add_reviewers'])->setName('reviewers')->setControlID('add-reviewers')->setControlStyle($enable_reviewers ? null : 'display: none')->setID('add-reviewers-tokenizer')->setDisableBehavior(true)->setDatasource($reviewer_source))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Add Subscribers'))->setName('ccs')->setControlID('add-ccs')->setControlStyle($enable_ccs ? null : 'display: none')->setID('add-ccs-tokenizer')->setDisableBehavior(true)->setDatasource($mailable_source))->appendChild(id(new PhabricatorRemarkupControl())->setName('comment')->setID('comment-content')->setLabel(pht('Comment'))->setValue($this->draft ? $this->draft->getDraft() : null)->setViewer($viewer))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit')));
     Javelin::initBehavior('differential-add-reviewers-and-ccs', array('dynamic' => array('add-reviewers-tokenizer' => array('actions' => array('request_review' => 1, 'add_reviewers' => 1, 'resign' => 1), 'src' => $reviewer_source->getDatasourceURI(), 'value' => $this->reviewers, 'row' => 'add-reviewers', 'labels' => $add_reviewers_labels, 'placeholder' => $reviewer_source->getPlaceholderText()), 'add-ccs-tokenizer' => array('actions' => array('add_ccs' => 1), 'src' => $mailable_source->getDatasourceURI(), 'value' => $this->ccs, 'row' => 'add-ccs', 'placeholder' => $mailable_source->getPlaceholderText())), 'select' => 'comment-action'));
     $diff = $revision->loadActiveDiff();
     $rev_id = $revision->getID();
     Javelin::initBehavior('differential-feedback-preview', array('uri' => '/differential/comment/preview/' . $rev_id . '/', 'preview' => 'comment-preview', 'action' => 'comment-action', 'content' => 'comment-content', 'previewTokenizers' => array('reviewers' => 'add-reviewers-tokenizer', 'ccs' => 'add-ccs-tokenizer'), 'inlineuri' => '/differential/comment/inline/preview/' . $rev_id . '/', 'inline' => 'inline-comment-preview'));
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     $header_text = $is_serious ? pht('Add Comment') : pht('Leap Into Action!');
     $header = id(new PHUIHeaderView())->setHeader($header_text);
     $anchor = id(new PhabricatorAnchorView())->setAnchorName('comment')->setNavigationMarker(true);
     $loading = phutil_tag('span', array('class' => 'aphront-panel-preview-loading-text'), pht('Loading comment preview...'));
     $preview = phutil_tag_div('aphront-panel-preview aphront-panel-flush', array(phutil_tag('div', array('id' => 'comment-preview'), $loading), phutil_tag('div', array('id' => 'inline-comment-preview'))));
     $comment_box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($anchor)->appendChild($form);
     if ($this->errorView) {
         $comment_box->setInfoView($this->errorView);
     }
     return array($comment_box, $preview);
 }
 public function renderView()
 {
     $data = $this->getStoryData();
     $author_phid = $data->getAuthorPHID();
     $view = new PhabricatorFeedStoryView();
     $revision_phid = $data->getValue('revision_phid');
     $action = $data->getValue('action');
     $verb = DifferentialAction::getActionPastTenseVerb($action);
     $view->setTitle($this->linkTo($author_phid) . " {$verb} revision " . $this->linkTo($revision_phid) . '.');
     $view->setEpoch($data->getEpoch());
     $action = $data->getValue('action');
     switch ($action) {
         case DifferentialAction::ACTION_CREATE:
         case DifferentialAction::ACTION_COMMIT:
             $full_size = true;
             break;
         default:
             $full_size = false;
             break;
     }
     if ($full_size) {
         $view->setImage($this->getHandle($author_phid)->getImageURI());
         $content = $this->renderSummary($data->getValue('feedback_content'));
         $view->appendChild($content);
     } else {
         $view->setOneLineStory(true);
     }
     return $view;
 }
 private function getLineForData($data)
 {
     $actor_phid = $data->getAuthorPHID();
     $owner_phid = $data->getValue('revision_author_phid');
     $revision_phid = $data->getValue('revision_phid');
     $action = $data->getValue('action');
     $actor_link = $this->linkTo($actor_phid);
     $revision_link = $this->linkTo($revision_phid);
     $owner_link = $this->linkTo($owner_phid);
     $verb = DifferentialAction::getActionPastTenseVerb($action);
     $one_line = "{$actor_link} {$verb} revision {$revision_link}";
     return $one_line;
 }
 public function render()
 {
     require_celerity_resource('differential-revision-add-comment-css');
     $revision = $this->revision;
     $actions = array();
     foreach ($this->actions as $action) {
         $actions[$action] = DifferentialAction::getActionVerb($action);
     }
     $form = new AphrontFormView();
     $form->setUser($this->user)->setAction($this->actionURI)->addHiddenInput('revision_id', $revision->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setID('comment-action')->setOptions($actions))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Add Reviewers')->setName('reviewers')->setControlID('add-reviewers')->setControlStyle('display: none')->setID('add-reviewers-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Add CCs')->setName('ccs')->setControlID('add-ccs')->setControlStyle('display: none')->setID('add-ccs-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTextAreaControl())->setName('comment')->setID('comment-content')->setLabel('Comment')->setEnableDragAndDropFileUploads(true)->setValue($this->draft))->appendChild(id(new AphrontFormSubmitControl())->setValue('Clowncopterize'));
     Javelin::initBehavior('differential-add-reviewers-and-ccs', array('dynamic' => array('add_reviewers' => array('tokenizer' => 'add-reviewers-tokenizer', 'src' => '/typeahead/common/users/', 'row' => 'add-reviewers'), 'add_ccs' => array('tokenizer' => 'add-ccs-tokenizer', 'src' => '/typeahead/common/mailable/', 'row' => 'add-ccs')), 'select' => 'comment-action'));
     $diff = $revision->loadActiveDiff();
     $lint_warning = null;
     $unit_warning = null;
     if ($diff->getLintStatus() >= DifferentialLintStatus::LINT_WARN) {
         $titles = array(DifferentialLintStatus::LINT_WARN => 'Lint Warning', DifferentialLintStatus::LINT_FAIL => 'Lint Failure', DifferentialLintStatus::LINT_SKIP => 'Lint Skipped');
         $content = "<p>This diff has Lint Problems. Make sure you are OK with them " . "before you accept this diff.</p>";
         $lint_warning = $this->generateWarningView($diff->getLintStatus(), $titles, 'lint-warning', $content);
     }
     if ($diff->getUnitStatus() >= DifferentialUnitStatus::UNIT_WARN) {
         $titles = array(DifferentialUnitStatus::UNIT_WARN => 'Unit Tests Warning', DifferentialUnitStatus::UNIT_FAIL => 'Unit Tests Failure', DifferentialUnitStatus::UNIT_SKIP => 'Unit Tests Skipped', DifferentialUnitStatus::UNIT_POSTPONED => 'Unit Tests Postponed');
         $content = "<p>This diff has Unit Test Problems. Make sure you are OK with them " . "before you accept this diff.</p>";
         $unit_warning = $this->generateWarningView($diff->getUnitStatus(), $titles, 'unit-warning', $content);
     }
     Javelin::initBehavior('differential-accept-with-errors', array('select' => 'comment-action', 'lint_warning' => $lint_warning ? 'lint-warning' : null, 'unit_warning' => $unit_warning ? 'unit-warning' : null));
     $rev_id = $revision->getID();
     Javelin::initBehavior('differential-feedback-preview', array('uri' => '/differential/comment/preview/' . $rev_id . '/', 'preview' => 'comment-preview', 'action' => 'comment-action', 'content' => 'comment-content', 'inlineuri' => '/differential/comment/inline/preview/' . $rev_id . '/', 'inline' => 'inline-comment-preview'));
     $panel_view = new AphrontPanelView();
     $panel_view->appendChild($form);
     if ($lint_warning) {
         $panel_view->appendChild($lint_warning);
     }
     if ($unit_warning) {
         $panel_view->appendChild($unit_warning);
     }
     $panel_view->setHeader('Leap Into Action');
     $panel_view->addClass('aphront-panel-accent');
     $panel_view->addClass('aphront-panel-flush');
     return '<div class="differential-add-comment-panel">' . $panel_view->render() . '<div class="aphront-panel-preview aphront-panel-flush">' . '<div id="comment-preview">' . '<span class="aphront-panel-preview-loading-text">' . 'Loading comment preview...' . '</span>' . '</div>' . '<div id="inline-comment-preview">' . '</div>' . '</div>' . '</div>';
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($request->isFormPost()) {
         $phid_arr = $request->getArr('view_user');
         $view_target = head($phid_arr);
         return id(new AphrontRedirectResponse())->setURI($request->getRequestURI()->alter('phid', $view_target));
     }
     $params = array_filter(array('phid' => $request->getStr('phid')));
     // Fill in the defaults we'll actually use for calculations if any
     // parameters are missing.
     $params += array('phid' => $user->getPHID());
     $side_nav = new AphrontSideNavFilterView();
     $side_nav->setBaseURI(id(new PhutilURI('/differential/stats/'))->alter('phid', $params['phid']));
     foreach (array(DifferentialAction::ACTION_CLOSE, DifferentialAction::ACTION_ACCEPT, DifferentialAction::ACTION_REJECT, DifferentialAction::ACTION_UPDATE, DifferentialAction::ACTION_COMMENT) as $action) {
         $verb = ucfirst(DifferentialAction::getActionPastTenseVerb($action));
         $side_nav->addFilter($action, $verb);
     }
     $this->filter = $side_nav->selectFilter($this->filter, DifferentialAction::ACTION_CLOSE);
     $panels = array();
     $handles = $this->loadViewerHandles(array($params['phid']));
     $filter_form = id(new AphrontFormView())->setAction('/differential/stats/' . $this->filter . '/')->setUser($user);
     $filter_form->appendChild($this->renderControl($params['phid'], $handles));
     $filter_form->appendChild(id(new AphrontFormSubmitControl())->setValue('Filter Revisions'));
     $side_nav->appendChild($filter_form);
     $comments = $this->loadComments($params['phid']);
     $revisions = $this->loadRevisions($params['phid']);
     $diffs = $this->loadDiffs($revisions);
     $panel = new AphrontPanelView();
     $panel->setHeader('Differential rate analysis');
     $panel->appendChild(id(new DifferentialRevisionStatsView())->setComments($comments)->setFilter($this->filter)->setRevisions($revisions)->setDiffs($diffs)->setUser($user));
     $panels[] = $panel;
     foreach ($panels as $panel) {
         $side_nav->appendChild($panel);
     }
     return $this->buildStandardPageResponse($side_nav, array('title' => 'Differential statistics'));
 }
 public function renderView()
 {
     $data = $this->getStoryData();
     $handles = $this->getHandles();
     $author_phid = $data->getAuthorPHID();
     $objects = $this->getObjects();
     $view = new PhabricatorFeedStoryView();
     $revision_phid = $data->getValue('revision_phid');
     $action = $data->getValue('action');
     $verb = DifferentialAction::getActionPastTenseVerb($action);
     $view->setTitle('<strong>' . $handles[$author_phid]->renderLink() . '</strong>' . ' ' . $verb . ' revision ' . '<strong>' . $handles[$revision_phid]->renderLink() . '</strong>.');
     $view->setEpoch($data->getEpoch());
     $action = $data->getValue('action');
     switch ($action) {
         case DifferentialAction::ACTION_CREATE:
         case DifferentialAction::ACTION_COMMIT:
             $full_size = true;
             break;
         default:
             $full_size = false;
             break;
     }
     if ($full_size) {
         if (!empty($objects[$author_phid])) {
             $image_phid = $objects[$author_phid]->getProfileImagePHID();
             $image_uri = PhabricatorFileURI::getViewURIForPHID($image_phid);
             $view->setImage($image_uri);
         }
         $content = phutil_escape_html($data->getValue('feedback_content'));
         $content = str_replace("\n", '<br />', $content);
         $view->appendChild($content);
     } else {
         $view->setOneLineStory(true);
     }
     return $view;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $author_phid = $request->getUser()->getPHID();
     $action = $request->getStr('action');
     $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
     $comment = new DifferentialComment();
     $comment->setContent($request->getStr('content'));
     $comment->setAction($action);
     $comment->setAuthorPHID($author_phid);
     $handles = array($author_phid);
     $reviewers = $request->getStrList('reviewers');
     if (DifferentialAction::allowReviewers($action) && $reviewers) {
         $comment->setMetadata(array(DifferentialComment::METADATA_ADDED_REVIEWERS => $reviewers));
         $handles = array_merge($handles, $reviewers);
     }
     $ccs = $request->getStrList('ccs');
     if ($action == DifferentialAction::ACTION_ADDCCS && $ccs) {
         $comment->setMetadata(array(DifferentialComment::METADATA_ADDED_CCS => $ccs));
         $handles = array_merge($handles, $ccs);
     }
     $handles = $this->loadViewerHandles($handles);
     $view = new DifferentialRevisionCommentView();
     $view->setUser($request->getUser());
     $view->setComment($comment);
     $view->setHandles($handles);
     $view->setMarkupEngine($engine);
     $view->setPreview(true);
     $view->setTargetDiff(null);
     $metadata = array('reviewers' => $reviewers, 'ccs' => $ccs);
     if ($action != DifferentialAction::ACTION_COMMENT) {
         $metadata['action'] = $action;
     }
     id(new PhabricatorDraft())->setAuthorPHID($author_phid)->setDraftKey('differential-comment-' . $this->id)->setDraft($comment->getContent())->setMetadata($metadata)->replaceOrDelete();
     return id(new AphrontAjaxResponse())->setContent($view->render());
 }
 public function getTitle()
 {
     $author_phid = $this->getAuthorPHID();
     $author_handle = $this->renderHandleLink($author_phid);
     $old = $this->getOldValue();
     $new = $this->getNewValue();
     switch ($this->getTransactionType()) {
         case self::TYPE_INLINE:
             return pht('%s added inline comments.', $author_handle);
         case self::TYPE_UPDATE:
             if ($this->getMetadataValue('isCommitUpdate')) {
                 return pht('This revision was automatically updated to reflect the ' . 'committed changes.');
             } else {
                 if ($new) {
                     // TODO: Migrate to PHIDs and use handles here?
                     if (phid_get_type($new) == DifferentialDiffPHIDType::TYPECONST) {
                         return pht('%s updated this revision to %s.', $author_handle, $this->renderHandleLink($new));
                     } else {
                         return pht('%s updated this revision.', $author_handle);
                     }
                 } else {
                     return pht('%s updated this revision.', $author_handle);
                 }
             }
         case self::TYPE_ACTION:
             switch ($new) {
                 case DifferentialAction::ACTION_CLOSE:
                     if (!$this->getMetadataValue('isCommitClose')) {
                         return DifferentialAction::getBasicStoryText($new, $author_handle);
                     }
                     $commit_name = $this->renderHandleLink($this->getMetadataValue('commitPHID'));
                     $committer_phid = $this->getMetadataValue('committerPHID');
                     $author_phid = $this->getMetadataValue('authorPHID');
                     if ($this->getHandleIfExists($committer_phid)) {
                         $committer_name = $this->renderHandleLink($committer_phid);
                     } else {
                         $committer_name = $this->getMetadataValue('committerName');
                     }
                     if ($this->getHandleIfExists($author_phid)) {
                         $author_name = $this->renderHandleLink($author_phid);
                     } else {
                         $author_name = $this->getMetadataValue('authorName');
                     }
                     if ($committer_name && $committer_name != $author_name) {
                         return pht('Closed by commit %s (authored by %s, committed by %s).', $commit_name, $author_name, $committer_name);
                     } else {
                         return pht('Closed by commit %s (authored by %s).', $commit_name, $author_name);
                     }
                     break;
                 default:
                     return DifferentialAction::getBasicStoryText($new, $author_handle);
             }
             break;
         case self::TYPE_STATUS:
             switch ($this->getNewValue()) {
                 case ArcanistDifferentialRevisionStatus::ACCEPTED:
                     return pht('This revision is now accepted and ready to land.');
                 case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
                     return pht('This revision now requires changes to proceed.');
                 case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                     return pht('This revision now requires review to proceed.');
             }
     }
     return parent::getTitle();
 }
 public function render()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     require_celerity_resource('phabricator-remarkup-css');
     require_celerity_resource('differential-revision-comment-css');
     $comment = $this->comment;
     $action = $comment->getAction();
     $action_class = 'differential-comment-action-' . phutil_escape_html($action);
     if ($this->preview) {
         $date = 'COMMENT PREVIEW';
     } else {
         $date = phabricator_datetime($comment->getDateCreated(), $this->user);
     }
     $info = array($date);
     $comment_anchor = null;
     $num = $this->commentNumber;
     if ($num && !$this->preview) {
         Javelin::initBehavior('phabricator-watch-anchor');
         $info[] = phutil_render_tag('a', array('name' => 'comment-' . $num, 'href' => '#comment-' . $num), 'Comment D' . $comment->getRevisionID() . '#' . $num);
         $comment_anchor = 'anchor-comment-' . $num;
     }
     $info = implode(' &middot; ', $info);
     $author = $this->handles[$comment->getAuthorPHID()];
     $author_link = $author->renderLink();
     $verb = DifferentialAction::getActionPastTenseVerb($comment->getAction());
     $verb = phutil_escape_html($verb);
     $content = $comment->getContent();
     $head_content = null;
     if (strlen(rtrim($content))) {
         $title = "{$author_link} {$verb} this revision:";
         $cache = $comment->getCache();
         if (strlen($cache)) {
             $content = $cache;
         } else {
             $content = $this->markupEngine->markupText($content);
             if ($comment->getID()) {
                 $comment->setCache($content);
                 $comment->save();
             }
         }
         $content = '<div class="phabricator-remarkup">' . $content . '</div>';
     } else {
         $title = null;
         $head_content = '<div class="differential-comment-nocontent">' . "<p>{$author_link} {$verb} this revision.</p>" . '</div>';
         $content = null;
     }
     if ($this->inlines) {
         $inline_render = array();
         $inlines = $this->inlines;
         $changesets = $this->changesets;
         $inlines_by_changeset = mgroup($inlines, 'getChangesetID');
         $inlines_by_changeset = array_select_keys($inlines_by_changeset, array_keys($this->changesets));
         $inline_render[] = '<table class="differential-inline-summary">';
         foreach ($inlines_by_changeset as $changeset_id => $inlines) {
             $changeset = $changesets[$changeset_id];
             $inlines = msort($inlines, 'getLineNumber');
             $inline_render[] = '<tr>' . '<th colspan="2">' . phutil_escape_html($changeset->getFileName()) . '</th>' . '</tr>';
             foreach ($inlines as $inline) {
                 if (!$inline->getLineLength()) {
                     $lines = $inline->getLineNumber();
                 } else {
                     $lines = $inline->getLineNumber() . "–" . ($inline->getLineNumber() + $inline->getLineLength());
                 }
                 if (!$this->target || $changeset->getDiffID() === $this->target->getID()) {
                     $lines = phutil_render_tag('a', array('href' => '#inline-' . $inline->getID(), 'class' => 'num'), $lines);
                 }
                 $inline_content = $inline->getContent();
                 if (strlen($inline_content)) {
                     $inline_cache = $inline->getCache();
                     if ($inline_cache) {
                         $inline_content = $inline_cache;
                     } else {
                         $inline_content = $this->markupEngine->markupText($inline_content);
                         if ($inline->getID()) {
                             $inline->setCache($inline_content);
                             $inline->save();
                         }
                     }
                 }
                 $inline_render[] = '<tr>' . '<td class="inline-line-number">' . $lines . '</td>' . '<td>' . '<div class="phabricator-remarkup">' . $inline_content . '</div>' . '</td>' . '</tr>';
             }
         }
         $inline_render[] = '</table>';
         $inline_render = implode("\n", $inline_render);
         $inline_render = '<div class="differential-inline-summary-section">' . 'Inline Comments' . '</div>' . $inline_render;
     } else {
         $inline_render = null;
     }
     $background = null;
     $uri = $author->getImageURI();
     if ($uri) {
         $background = "background-image: url('{$uri}');";
     }
     $metadata_blocks = array();
     $metadata = $comment->getMetadata();
     $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS);
     if ($added_reviewers) {
         $reviewers = 'Added reviewers: ' . $this->renderHandleList($added_reviewers);
         $metadata_blocks[] = $reviewers;
     }
     $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS);
     if ($added_ccs) {
         $ccs = 'Added CCs: ' . $this->renderHandleList($added_ccs);
         $metadata_blocks[] = $ccs;
     }
     if ($metadata_blocks) {
         $metadata_blocks = '<div class="differential-comment-metadata">' . implode("\n", $metadata_blocks) . '</div>';
     } else {
         $metadata_blocks = null;
     }
     return phutil_render_tag('div', array('class' => "differential-comment {$action_class}", 'id' => $comment_anchor), '<div class="differential-comment-head">' . '<span class="differential-comment-info">' . $info . '</span>' . '<span class="differential-comment-title">' . $title . '</span>' . '<div style="clear: both;"></div>' . '</div>' . '<div class="differential-comment-body" style="' . $background . '">' . '<div class="differential-comment-content">' . $head_content . $metadata_blocks . '<div class="differential-comment-core">' . $content . '</div>' . $inline_render . '</div>' . '</div>');
 }
 public function renderForAsanaBridge($implied_context = false)
 {
     $data = $this->getStoryData();
     $comment = $data->getValue('feedback_content');
     $author_name = $this->getHandle($this->getAuthorPHID())->getName();
     $action = $this->getValue('action');
     $engine = PhabricatorMarkupEngine::newMarkupEngine(array())->setConfig('viewer', new PhabricatorUser())->setMode(PhutilRemarkupEngine::MODE_TEXT);
     $revision_phid = $this->getPrimaryObjectPHID();
     $revision_name = $this->getHandle($revision_phid)->getFullName();
     if ($implied_context) {
         $title = DifferentialAction::getBasicStoryText($action, $author_name);
     } else {
         switch ($action) {
             case DifferentialAction::ACTION_COMMENT:
                 $title = pht('%s commented on revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_ACCEPT:
                 $title = pht('%s accepted revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_REJECT:
                 $title = pht('%s requested changes to revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_RETHINK:
                 $title = pht('%s planned changes to revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_ABANDON:
                 $title = pht('%s abandoned revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_CLOSE:
                 $title = pht('%s closed revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_REQUEST:
                 $title = pht('%s requested a review of revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_RECLAIM:
                 $title = pht('%s reclaimed revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_UPDATE:
                 $title = pht('%s updated revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_RESIGN:
                 $title = pht('%s resigned from revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_SUMMARIZE:
                 $title = pht('%s summarized revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_TESTPLAN:
                 $title = pht('%s explained the test plan for revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_CREATE:
                 $title = pht('%s created revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_ADDREVIEWERS:
                 $title = pht('%s added reviewers to revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_ADDCCS:
                 $title = pht('%s added CCs to revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_CLAIM:
                 $title = pht('%s commandeered revision %s', $author_name, $revision_name);
                 break;
             case DifferentialAction::ACTION_REOPEN:
                 $title = pht('%s reopened revision %s', $author_name, $revision_name);
                 break;
             case DifferentialTransaction::TYPE_INLINE:
                 $title = pht('%s added inline comments to %s', $author_name, $revision_name);
                 break;
             default:
                 $title = pht('%s edited revision %s', $author_name, $revision_name);
                 break;
         }
     }
     if (strlen($comment)) {
         $comment = $engine->markupText($comment);
         $title .= "\n\n";
         $title .= $comment;
     }
     // Roughly render inlines into the comment.
     $xaction_phids = $data->getValue('temporaryTransactionPHIDs');
     if ($xaction_phids) {
         $inlines = id(new DifferentialTransactionQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs($xaction_phids)->needComments(true)->withTransactionTypes(array(DifferentialTransaction::TYPE_INLINE))->execute();
         if ($inlines) {
             $title .= "\n\n";
             $title .= pht('Inline Comments');
             $title .= "\n";
             $changeset_ids = array();
             foreach ($inlines as $inline) {
                 $changeset_ids[] = $inline->getComment()->getChangesetID();
             }
             $changesets = id(new DifferentialChangeset())->loadAllWhere('id IN (%Ld)', $changeset_ids);
             foreach ($inlines as $inline) {
                 $comment = $inline->getComment();
                 $changeset = idx($changesets, $comment->getChangesetID());
                 if (!$changeset) {
                     continue;
                 }
                 $filename = $changeset->getDisplayFilename();
                 $linenumber = $comment->getLineNumber();
                 $inline_text = $engine->markupText($comment->getContent());
                 $inline_text = rtrim($inline_text);
                 $title .= "{$filename}:{$linenumber} {$inline_text}\n";
             }
         }
     }
     return $title;
 }
 public function render()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     require_celerity_resource('phabricator-remarkup-css');
     require_celerity_resource('differential-revision-comment-css');
     $comment = $this->comment;
     $action = $comment->getAction();
     $action_class = 'differential-comment-action-' . $action;
     if ($this->preview) {
         $date = 'COMMENT PREVIEW';
     } else {
         $date = phabricator_datetime($comment->getDateCreated(), $this->user);
     }
     $info = array();
     $content_source = new PhabricatorContentSourceView();
     $content_source->setContentSource($comment->getContentSource());
     $content_source->setUser($this->user);
     $info[] = $content_source->render();
     $info[] = $date;
     $comment_anchor = null;
     $num = $this->commentNumber;
     if ($num && !$this->preview) {
         Javelin::initBehavior('phabricator-watch-anchor');
         $info[] = phutil_render_tag('a', array('name' => 'comment-' . $num, 'href' => '#comment-' . $num), 'Comment D' . $comment->getRevisionID() . '#' . $num);
         $comment_anchor = 'anchor-comment-' . $num;
     }
     $info = implode(' &middot; ', array_filter($info));
     $author = $this->handles[$comment->getAuthorPHID()];
     $author_link = $author->renderLink();
     $verb = DifferentialAction::getActionPastTenseVerb($comment->getAction());
     $verb = phutil_escape_html($verb);
     $content = $comment->getContent();
     $head_content = null;
     if (strlen(rtrim($content))) {
         $title = "{$author_link} {$verb} this revision:";
         $cache = $comment->getCache();
         if (strlen($cache)) {
             $content = $cache;
         } else {
             $content = $this->markupEngine->markupText($content);
             if ($comment->getID()) {
                 $comment->setCache($content);
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
                 $comment->save();
                 unset($unguarded);
             }
         }
         $content = '<div class="phabricator-remarkup">' . $content . '</div>';
     } else {
         $title = null;
         $head_content = '<div class="differential-comment-nocontent">' . "<p>{$author_link} {$verb} this revision.</p>" . '</div>';
         $content = null;
     }
     if ($this->inlines) {
         $inline_render = array();
         $inlines = $this->inlines;
         $changesets = $this->changesets;
         $inlines_by_changeset = mgroup($inlines, 'getChangesetID');
         $inlines_by_changeset = array_select_keys($inlines_by_changeset, array_keys($this->changesets));
         $inline_render[] = '<table class="differential-inline-summary">';
         foreach ($inlines_by_changeset as $changeset_id => $inlines) {
             $changeset = $changesets[$changeset_id];
             $inlines = msort($inlines, 'getLineNumber');
             $inline_render[] = '<tr>' . '<th colspan="3">' . phutil_escape_html($changeset->getFileName()) . '</th>' . '</tr>';
             foreach ($inlines as $inline) {
                 if (!$inline->getLineLength()) {
                     $lines = $inline->getLineNumber();
                 } else {
                     $lines = $inline->getLineNumber() . "–" . ($inline->getLineNumber() + $inline->getLineLength());
                 }
                 $on_target = $this->target && $this->target->getID() == $changeset->getDiffID();
                 $is_visible = false;
                 if ($inline->getIsNewFile()) {
                     // This comment is on the right side of the versus diff, and visible
                     // on the left side of the page.
                     if ($this->versusDiffID) {
                         if ($changeset->getDiffID() == $this->versusDiffID) {
                             $is_visible = true;
                         }
                     }
                     // This comment is on the right side of the target diff, and visible
                     // on the right side of the page.
                     if ($on_target) {
                         $is_visible = true;
                     }
                 } else {
                     // Ths comment is on the left side of the target diff, and visible
                     // on the left side of the page.
                     if (!$this->versusDiffID) {
                         if ($on_target) {
                             $is_visible = true;
                         }
                     }
                     // TODO: We still get one edge case wrong here, when we have a
                     // versus diff and the file didn't exist in the old version. The
                     // comment is visible because we show the left side of the target
                     // diff when there's no corresponding file in the versus diff, but
                     // we incorrectly link it off-page.
                 }
                 $where = null;
                 if ($is_visible) {
                     $lines = phutil_render_tag('a', array('href' => '#inline-' . $inline->getID(), 'class' => 'num'), $lines);
                 } else {
                     $diff_id = $changeset->getDiffID();
                     $lines = phutil_render_tag('a', array('href' => '?id=' . $diff_id . '#inline-' . $inline->getID(), 'class' => 'num', 'target' => '_blank'), $lines . " ↗");
                     $where = '(On Diff #' . $diff_id . ')';
                 }
                 $inline_content = $inline->getContent();
                 if (strlen($inline_content)) {
                     $inline_cache = $inline->getCache();
                     if ($inline_cache) {
                         $inline_content = $inline_cache;
                     } else {
                         $inline_content = $this->markupEngine->markupText($inline_content);
                         if ($inline->getID()) {
                             $inline->setCache($inline_content);
                             $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
                             $inline->save();
                             unset($unguarded);
                         }
                     }
                 }
                 $inline_render[] = '<tr>' . '<td class="inline-line-number">' . $lines . '</td>' . '<td class="inline-which-diff">' . $where . '</td>' . '<td>' . '<div class="phabricator-remarkup">' . $inline_content . '</div>' . '</td>' . '</tr>';
             }
         }
         $inline_render[] = '</table>';
         $inline_render = implode("\n", $inline_render);
         $inline_render = '<div class="differential-inline-summary-section">' . 'Inline Comments' . '</div>' . $inline_render;
     } else {
         $inline_render = null;
     }
     $background = null;
     $uri = $author->getImageURI();
     if ($uri) {
         $background = "background-image: url('{$uri}');";
     }
     $metadata_blocks = array();
     $metadata = $comment->getMetadata();
     $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS);
     if ($added_reviewers) {
         $reviewers = 'Added reviewers: ' . $this->renderHandleList($added_reviewers);
         $metadata_blocks[] = $reviewers;
     }
     $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS);
     if ($added_ccs) {
         $ccs = 'Added CCs: ' . $this->renderHandleList($added_ccs);
         $metadata_blocks[] = $ccs;
     }
     if ($metadata_blocks) {
         $metadata_blocks = '<div class="differential-comment-metadata">' . implode("\n", $metadata_blocks) . '</div>';
     } else {
         $metadata_blocks = null;
     }
     return phutil_render_tag('div', array('class' => "differential-comment {$action_class}", 'id' => $comment_anchor), '<div class="differential-comment-head">' . '<span class="differential-comment-info">' . $info . '</span>' . '<span class="differential-comment-title">' . $title . '</span>' . '<div style="clear: both;"></div>' . '</div>' . '<div class="differential-comment-body" style="' . $background . '">' . '<div class="differential-comment-content">' . $head_content . $metadata_blocks . '<div class="differential-comment-core">' . $content . '</div>' . $inline_render . '</div>' . '</div>');
 }
 public function getTitle()
 {
     $author_phid = $this->getAuthorPHID();
     $author_handle = $this->renderHandleLink($author_phid);
     $old = $this->getOldValue();
     $new = $this->getNewValue();
     switch ($this->getTransactionType()) {
         case self::TYPE_INLINE:
             return pht('%s added inline comments.', $author_handle);
         case self::TYPE_UPDATE:
             if ($new) {
                 // TODO: Migrate to PHIDs and use handles here?
                 if (phid_get_type($new) == DifferentialDiffPHIDType::TYPECONST) {
                     return pht('%s updated this revision to %s.', $author_handle, $this->renderHandleLink($new));
                 } else {
                     return pht('%s updated this revision.', $author_handle);
                 }
             } else {
                 return pht('%s updated this revision.', $author_handle);
             }
         case self::TYPE_ACTION:
             return DifferentialAction::getBasicStoryText($new, $author_handle);
         case self::TYPE_STATUS:
             switch ($this->getNewValue()) {
                 case ArcanistDifferentialRevisionStatus::ACCEPTED:
                     return pht('This revision is now accepted and ready to land.');
                 case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
                     return pht('This revision now requires changes to proceed.');
                 case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                     return pht('This revision now requires review to proceed.');
             }
     }
     return parent::getTitle();
 }
 private function getRevisionCommentActions(DifferentialRevision $revision)
 {
     $actions = array(DifferentialAction::ACTION_COMMENT => true);
     $admin_actions = array();
     $viewer = $this->getRequest()->getUser();
     $viewer_phid = $viewer->getPHID();
     $viewer_is_admin = $viewer->getIsAdmin();
     $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID();
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $viewer_did_accept = $viewer_phid === $revision->loadReviewedBy();
     if ($viewer_is_owner) {
         switch ($revision->getStatus()) {
             case DifferentialRevisionStatus::NEEDS_REVIEW:
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 break;
             case DifferentialRevisionStatus::NEEDS_REVISION:
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 break;
             case DifferentialRevisionStatus::ACCEPTED:
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 break;
             case DifferentialRevisionStatus::COMMITTED:
                 break;
             case DifferentialRevisionStatus::ABANDONED:
                 $actions[DifferentialAction::ACTION_RECLAIM] = true;
                 break;
         }
     } else {
         switch ($revision->getStatus()) {
             case DifferentialRevisionStatus::NEEDS_REVIEW:
                 $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin;
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case DifferentialRevisionStatus::NEEDS_REVISION:
                 $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin;
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case DifferentialRevisionStatus::ACCEPTED:
                 $admin_actions[DifferentialAction::ACTION_ABANDON] = $viewer_is_admin;
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer && !$viewer_did_accept;
                 break;
             case DifferentialRevisionStatus::COMMITTED:
             case DifferentialRevisionStatus::ABANDONED:
                 break;
         }
     }
     $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true;
     $actions[DifferentialAction::ACTION_ADDCCS] = true;
     $actions = array_keys(array_filter($actions));
     $admin_actions = array_keys(array_filter($admin_actions));
     $actions_dict = array();
     foreach ($actions as $action) {
         $actions_dict[$action] = DifferentialAction::getActionVerb($action);
     }
     foreach ($admin_actions as $action) {
         $actions_dict[$action] = '(Admin) ' . DifferentialAction::getActionVerb($action);
     }
     return $actions_dict;
 }
 private function getRevisionCommentActions(DifferentialRevision $revision)
 {
     $actions = array(DifferentialAction::ACTION_COMMENT => true);
     $viewer = $this->getRequest()->getUser();
     $viewer_phid = $viewer->getPHID();
     $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID();
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $viewer_did_accept = $viewer_phid === $revision->loadReviewedBy();
     $status = $revision->getStatus();
     $allow_self_accept = PhabricatorEnv::getEnvConfig('differential.allow-self-accept', false);
     if ($viewer_is_owner) {
         switch ($status) {
             case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                 $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
                 $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::ACCEPTED:
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 $actions[DifferentialAction::ACTION_CLOSE] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::CLOSED:
                 break;
             case ArcanistDifferentialRevisionStatus::ABANDONED:
                 $actions[DifferentialAction::ACTION_RECLAIM] = true;
                 break;
         }
     } else {
         switch ($status) {
             case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case ArcanistDifferentialRevisionStatus::ACCEPTED:
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer && !$viewer_did_accept;
                 break;
             case ArcanistDifferentialRevisionStatus::CLOSED:
             case ArcanistDifferentialRevisionStatus::ABANDONED:
                 break;
         }
         if ($status != ArcanistDifferentialRevisionStatus::CLOSED) {
             $actions[DifferentialAction::ACTION_CLAIM] = true;
         }
     }
     $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true;
     $actions[DifferentialAction::ACTION_ADDCCS] = true;
     $actions = array_keys(array_filter($actions));
     $actions_dict = array();
     foreach ($actions as $action) {
         $actions_dict[$action] = DifferentialAction::getActionVerb($action);
     }
     return $actions_dict;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $revision = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($id))->executeOne();
     if (!$revision) {
         return new Aphront404Response();
     }
     $type_comment = PhabricatorTransactions::TYPE_COMMENT;
     $type_action = DifferentialTransaction::TYPE_ACTION;
     $type_edge = PhabricatorTransactions::TYPE_EDGE;
     $type_subscribers = PhabricatorTransactions::TYPE_SUBSCRIBERS;
     $xactions = array();
     $action = $request->getStr('action');
     switch ($action) {
         case DifferentialAction::ACTION_COMMENT:
         case DifferentialAction::ACTION_ADDREVIEWERS:
         case DifferentialAction::ACTION_ADDCCS:
             break;
         default:
             $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_action)->setNewValue($action);
             break;
     }
     $edge_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST;
     $reviewers = $request->getStrList('reviewers');
     if (DifferentialAction::allowReviewers($action) && $reviewers) {
         $faux_edges = array();
         foreach ($reviewers as $phid) {
             $faux_edges[$phid] = array('src' => $revision->getPHID(), 'type' => $edge_reviewer, 'dst' => $phid);
         }
         $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_edge)->setMetadataValue('edge:type', $edge_reviewer)->setOldValue(array())->setNewValue($faux_edges);
     }
     $ccs = $request->getStrList('ccs');
     if ($ccs) {
         $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_subscribers)->setOldValue(array())->setNewValue(array_fuse($ccs));
     }
     // Add a comment transaction if there's nothing, so we'll generate a
     // nonempty result.
     if (strlen($request->getStr('content')) || !$xactions) {
         $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_comment)->attachComment(id(new ManiphestTransactionComment())->setContent($request->getStr('content')));
     }
     foreach ($xactions as $xaction) {
         $xaction->setAuthorPHID($viewer->getPHID());
     }
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($request->getUser());
     foreach ($xactions as $xaction) {
         if ($xaction->hasComment()) {
             $engine->addObject($xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
         }
     }
     $engine->process();
     $phids = mpull($xactions, 'getRequiredHandlePHIDs');
     $phids = array_mergev($phids);
     $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs($phids)->execute();
     foreach ($xactions as $xaction) {
         $xaction->setHandles($handles);
     }
     $view = id(new DifferentialTransactionView())->setUser($viewer)->setTransactions($xactions)->setIsPreview(true);
     $metadata = array('reviewers' => $reviewers, 'ccs' => $ccs);
     if ($action != DifferentialAction::ACTION_COMMENT) {
         $metadata['action'] = $action;
     }
     $draft_key = 'differential-comment-' . $id;
     $draft = id(new PhabricatorDraft())->setAuthorPHID($viewer->getPHID())->setDraftKey($draft_key)->setDraft($request->getStr('content'))->setMetadata($metadata)->replaceOrDelete();
     if ($draft->isDeleted()) {
         DifferentialDraft::deleteHasDraft($viewer->getPHID(), $revision->getPHID(), $draft_key);
     } else {
         DifferentialDraft::markHasDraft($viewer->getPHID(), $revision->getPHID(), $draft_key);
     }
     return id(new AphrontAjaxResponse())->setContent((string) phutil_implode_html('', $view->buildEvents()));
 }
 public function render()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before rendering!");
     }
     require_celerity_resource('phabricator-remarkup-css');
     require_celerity_resource('differential-revision-comment-css');
     $comment = $this->comment;
     $action = $comment->getAction();
     $action_class = 'differential-comment-action-' . $action;
     $info = array();
     $content = $comment->getContent();
     $hide_comments = true;
     if (strlen(rtrim($content))) {
         $hide_comments = false;
         $cache = $comment->getCache();
         if (strlen($cache)) {
             $content = $cache;
         } else {
             $content = $this->markupEngine->markupText($content);
             if ($comment->getID()) {
                 $comment->setCache($content);
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
                 $comment->save();
                 unset($unguarded);
             }
         }
         $content = '<div class="phabricator-remarkup">' . $content . '</div>';
     }
     $inline_render = $this->renderInlineComments();
     if ($inline_render) {
         $hide_comments = false;
     }
     $author = $this->handles[$comment->getAuthorPHID()];
     $author_link = $author->renderLink();
     $metadata = $comment->getMetadata();
     $added_reviewers = idx($metadata, DifferentialComment::METADATA_ADDED_REVIEWERS, array());
     $added_ccs = idx($metadata, DifferentialComment::METADATA_ADDED_CCS, array());
     $verb = DifferentialAction::getActionPastTenseVerb($comment->getAction());
     $verb = phutil_escape_html($verb);
     $actions = array();
     switch ($comment->getAction()) {
         case DifferentialAction::ACTION_ADDCCS:
             $actions[] = "{$author_link} added CCs: " . $this->renderHandleList($added_ccs) . ".";
             $added_ccs = null;
             break;
         case DifferentialAction::ACTION_ADDREVIEWERS:
             $actions[] = "{$author_link} added reviewers: " . $this->renderHandleList($added_reviewers) . ".";
             $added_reviewers = null;
             break;
         case DifferentialAction::ACTION_UPDATE:
             $diff_id = idx($metadata, DifferentialComment::METADATA_DIFF_ID);
             if ($diff_id) {
                 $diff_link = phutil_render_tag('a', array('href' => '/D' . $comment->getRevisionID() . '?id=' . $diff_id), 'Diff #' . phutil_escape_html($diff_id));
                 $actions[] = "{$author_link} updated this revision to {$diff_link}.";
             } else {
                 $actions[] = "{$author_link} {$verb} this revision.";
             }
             break;
         default:
             $actions[] = "{$author_link} {$verb} this revision.";
             break;
     }
     if ($added_reviewers) {
         $actions[] = "{$author_link} added reviewers: " . $this->renderHandleList($added_reviewers) . ".";
     }
     if ($added_ccs) {
         $actions[] = "{$author_link} added CCs: " . $this->renderHandleList($added_ccs) . ".";
     }
     foreach ($actions as $key => $action) {
         $actions[$key] = '<div>' . $action . '</div>';
     }
     $xaction_view = id(new PhabricatorTransactionView())->setUser($this->user)->setImageURI($author->getImageURI())->setContentSource($comment->getContentSource())->addClass($action_class)->setActions($actions);
     if ($this->preview) {
         $xaction_view->setIsPreview($this->preview);
     } else {
         $xaction_view->setEpoch($comment->getDateCreated());
         if ($this->anchorName) {
             $anchor_name = $this->anchorName;
             $anchor_text = 'D' . $comment->getRevisionID() . '#' . $anchor_name;
             $xaction_view->setAnchor($anchor_name, $anchor_text);
         }
     }
     if (!$hide_comments) {
         $xaction_view->appendChild('<div class="differential-comment-core">' . $content . '</div>' . $this->renderSingleView($inline_render));
     }
     return $xaction_view->render();
 }
 private function getRevisionCommentActions(DifferentialRevision $revision)
 {
     $actions = array(DifferentialAction::ACTION_COMMENT => true);
     $viewer = $this->getRequest()->getUser();
     $viewer_phid = $viewer->getPHID();
     $viewer_is_owner = $viewer_phid == $revision->getAuthorPHID();
     $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers());
     $status = $revision->getStatus();
     $viewer_has_accepted = false;
     $viewer_has_rejected = false;
     $status_accepted = DifferentialReviewerStatus::STATUS_ACCEPTED;
     $status_rejected = DifferentialReviewerStatus::STATUS_REJECTED;
     foreach ($revision->getReviewerStatus() as $reviewer) {
         if ($reviewer->getReviewerPHID() == $viewer_phid) {
             if ($reviewer->getStatus() == $status_accepted) {
                 $viewer_has_accepted = true;
             }
             if ($reviewer->getStatus() == $status_rejected) {
                 $viewer_has_rejected = true;
             }
             break;
         }
     }
     $allow_self_accept = PhabricatorEnv::getEnvConfig('differential.allow-self-accept');
     $always_allow_abandon = PhabricatorEnv::getEnvConfig('differential.always-allow-abandon');
     $always_allow_close = PhabricatorEnv::getEnvConfig('differential.always-allow-close');
     $allow_reopen = PhabricatorEnv::getEnvConfig('differential.allow-reopen');
     if ($viewer_is_owner) {
         switch ($status) {
             case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                 $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
             case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
                 $actions[DifferentialAction::ACTION_ACCEPT] = $allow_self_accept;
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::ACCEPTED:
                 $actions[DifferentialAction::ACTION_ABANDON] = true;
                 $actions[DifferentialAction::ACTION_REQUEST] = true;
                 $actions[DifferentialAction::ACTION_RETHINK] = true;
                 $actions[DifferentialAction::ACTION_CLOSE] = true;
                 break;
             case ArcanistDifferentialRevisionStatus::CLOSED:
                 break;
             case ArcanistDifferentialRevisionStatus::ABANDONED:
                 $actions[DifferentialAction::ACTION_RECLAIM] = true;
                 break;
         }
     } else {
         switch ($status) {
             case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW:
                 $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case ArcanistDifferentialRevisionStatus::NEEDS_REVISION:
             case ArcanistDifferentialRevisionStatus::CHANGES_PLANNED:
                 $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
                 $actions[DifferentialAction::ACTION_ACCEPT] = true;
                 $actions[DifferentialAction::ACTION_REJECT] = !$viewer_has_rejected;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case ArcanistDifferentialRevisionStatus::ACCEPTED:
                 $actions[DifferentialAction::ACTION_ABANDON] = $always_allow_abandon;
                 $actions[DifferentialAction::ACTION_ACCEPT] = !$viewer_has_accepted;
                 $actions[DifferentialAction::ACTION_REJECT] = true;
                 $actions[DifferentialAction::ACTION_RESIGN] = $viewer_is_reviewer;
                 break;
             case ArcanistDifferentialRevisionStatus::CLOSED:
             case ArcanistDifferentialRevisionStatus::ABANDONED:
                 break;
         }
         if ($status != ArcanistDifferentialRevisionStatus::CLOSED) {
             $actions[DifferentialAction::ACTION_CLAIM] = true;
             $actions[DifferentialAction::ACTION_CLOSE] = $always_allow_close;
         }
     }
     $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true;
     $actions[DifferentialAction::ACTION_ADDCCS] = true;
     $actions[DifferentialAction::ACTION_REOPEN] = $allow_reopen && $status == ArcanistDifferentialRevisionStatus::CLOSED;
     $actions = array_keys(array_filter($actions));
     $actions_dict = array();
     foreach ($actions as $action) {
         $actions_dict[$action] = DifferentialAction::getActionVerb($action);
     }
     return $actions_dict;
 }
 public function render()
 {
     require_celerity_resource('differential-revision-add-comment-css');
     $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
     $revision = $this->revision;
     $action = null;
     if ($this->draft) {
         $action = idx($this->draft->getMetadata(), 'action');
     }
     $enable_reviewers = DifferentialAction::allowReviewers($action);
     $enable_ccs = $action == DifferentialAction::ACTION_ADDCCS;
     $form = new AphrontFormView();
     $form->setWorkflow(true)->setUser($this->user)->setAction($this->actionURI)->addHiddenInput('revision_id', $revision->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel('Action')->setName('action')->setValue($action)->setID('comment-action')->setOptions($this->actions))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Add Reviewers')->setName('reviewers')->setControlID('add-reviewers')->setControlStyle($enable_reviewers ? null : 'display: none')->setID('add-reviewers-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Add CCs')->setName('ccs')->setControlID('add-ccs')->setControlStyle($enable_ccs ? null : 'display: none')->setID('add-ccs-tokenizer')->setDisableBehavior(true))->appendChild(id(new PhabricatorRemarkupControl())->setName('comment')->setID('comment-content')->setLabel('Comment')->setValue($this->draft ? $this->draft->getDraft() : null))->appendChild(id(new AphrontFormSubmitControl())->setValue($is_serious ? 'Submit' : 'Clowncopterize'));
     Javelin::initBehavior('differential-add-reviewers-and-ccs', array('dynamic' => array('add-reviewers-tokenizer' => array('actions' => array('request_review' => 1, 'add_reviewers' => 1), 'src' => '/typeahead/common/users/', 'value' => $this->reviewers, 'row' => 'add-reviewers', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user name...'), 'add-ccs-tokenizer' => array('actions' => array('add_ccs' => 1), 'src' => '/typeahead/common/mailable/', 'value' => $this->ccs, 'row' => 'add-ccs', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user or mailing list...')), 'select' => 'comment-action'));
     $diff = $revision->loadActiveDiff();
     $warnings = mpull($this->auxFields, 'renderWarningBoxForRevisionAccept');
     $lint_warning = null;
     $unit_warning = null;
     Javelin::initBehavior('differential-accept-with-errors', array('select' => 'comment-action', 'warnings' => 'warnings'));
     $rev_id = $revision->getID();
     Javelin::initBehavior('differential-feedback-preview', array('uri' => '/differential/comment/preview/' . $rev_id . '/', 'preview' => 'comment-preview', 'action' => 'comment-action', 'content' => 'comment-content', 'previewTokenizers' => array('reviewers' => 'add-reviewers-tokenizer', 'ccs' => 'add-ccs-tokenizer'), 'inlineuri' => '/differential/comment/inline/preview/' . $rev_id . '/', 'inline' => 'inline-comment-preview'));
     $panel_view = new AphrontPanelView();
     $panel_view->appendChild($form);
     $warning_container = '<div id="warnings">';
     foreach ($warnings as $warning) {
         if ($warning) {
             $warning_container .= $warning->render();
         }
     }
     $warning_container .= '</div>';
     $panel_view->appendChild($warning_container);
     if ($lint_warning) {
         $panel_view->appendChild($lint_warning);
     }
     if ($unit_warning) {
         $panel_view->appendChild($unit_warning);
     }
     $panel_view->setHeader($is_serious ? 'Add Comment' : 'Leap Into Action');
     $panel_view->addClass('aphront-panel-accent');
     $panel_view->addClass('aphront-panel-flush');
     return id(new PhabricatorAnchorView())->setAnchorName('comment')->setNavigationMarker(true)->render() . '<div class="differential-add-comment-panel">' . $panel_view->render() . '<div class="aphront-panel-preview aphront-panel-flush">' . '<div id="comment-preview">' . '<span class="aphront-panel-preview-loading-text">' . 'Loading comment preview...' . '</span>' . '</div>' . '<div id="inline-comment-preview">' . '</div>' . '</div>' . '</div>';
 }