public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $inlines = $this->loadInlineComments(); assert_instances_of($inlines, 'PhabricatorInlineCommentInterface'); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); foreach ($inlines as $inline) { $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); $phids = array($user->getPHID()); $handles = $this->loadViewerHandles($phids); $views = array(); foreach ($inlines as $inline) { $view = new DifferentialInlineCommentView(); $view->setInlineComment($inline); $view->setMarkupEngine($engine); $view->setHandles($handles); $view->setEditable(false); $view->setPreview(true); $views[] = $view->render(); } $views = phutil_implode_html("\n", $views); return id(new AphrontAjaxResponse())->setContent($views); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $is_show_more = false; if (!$this->getTransactionID()) { $this->setTransactionID($this->getRequest()->getStr('ref')); $is_show_more = true; } $transaction_id = $this->getTransactionID(); $transaction = id(new ManiphestTransaction())->load($transaction_id); if (!$transaction) { return new Aphront404Response(); } $transactions = array($transaction); $phids = array(); foreach ($transactions as $xaction) { foreach ($xaction->extractPHIDs() as $phid) { $phids[$phid] = $phid; } } $handles = $this->loadViewerHandles($phids); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($transaction, ManiphestTransaction::MARKUP_FIELD_BODY); $engine->process(); $view = new ManiphestTransactionDetailView(); $view->setTransactionGroup($transactions); $view->setHandles($handles); $view->setUser($user); $view->setMarkupEngine($engine); $view->setRenderSummaryOnly(true); $view->setRenderFullSummary(true); $view->setRangeSpecification($request->getStr('range')); if ($is_show_more) { return id(new PhabricatorChangesetResponse())->setRenderedChangeset($view->render()); } else { return id(new AphrontAjaxResponse())->setContent($view->render()); } }
public function renderPropertyViewValue(array $handles) { $diff = $this->getObject()->getActiveDiff(); $ustar = DifferentialRevisionUpdateHistoryView::renderDiffUnitStar($diff); $umsg = DifferentialRevisionUpdateHistoryView::getDiffUnitMessage($diff); $rows = array(); $rows[] = array('style' => 'star', 'name' => $ustar, 'value' => $umsg, 'show' => true); $excuse = $diff->getProperty('arc:unit-excuse'); if ($excuse) { $rows[] = array('style' => 'excuse', 'name' => 'Excuse', 'value' => phutil_escape_html_newlines($excuse), 'show' => true); } $show_limit = 10; $hidden = array(); $udata = $diff->getProperty('arc:unit'); if ($udata) { $sort_map = array(ArcanistUnitTestResult::RESULT_BROKEN => 0, ArcanistUnitTestResult::RESULT_FAIL => 1, ArcanistUnitTestResult::RESULT_UNSOUND => 2, ArcanistUnitTestResult::RESULT_SKIP => 3, ArcanistUnitTestResult::RESULT_POSTPONED => 4, ArcanistUnitTestResult::RESULT_PASS => 5); foreach ($udata as $key => $test) { $udata[$key]['sort'] = idx($sort_map, idx($test, 'result')); } $udata = isort($udata, 'sort'); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($this->getViewer()); $markup_objects = array(); foreach ($udata as $key => $test) { $userdata = idx($test, 'userdata'); if ($userdata) { if ($userdata !== false) { $userdata = str_replace("", '', $userdata); } $markup_object = id(new PhabricatorMarkupOneOff())->setContent($userdata)->setPreserveLinebreaks(true); $engine->addObject($markup_object, 'default'); $markup_objects[$key] = $markup_object; } } $engine->process(); foreach ($udata as $key => $test) { $result = idx($test, 'result'); $default_hide = false; switch ($result) { case ArcanistUnitTestResult::RESULT_POSTPONED: case ArcanistUnitTestResult::RESULT_PASS: $default_hide = true; break; } if ($show_limit && !$default_hide) { --$show_limit; $show = true; } else { $show = false; if (empty($hidden[$result])) { $hidden[$result] = 0; } $hidden[$result]++; } $value = idx($test, 'name'); if (!empty($test['link'])) { $value = phutil_tag('a', array('href' => $test['link'], 'target' => '_blank'), $value); } $rows[] = array('style' => $this->getResultStyle($result), 'name' => ucwords($result), 'value' => $value, 'show' => $show); if (isset($markup_objects[$key])) { $rows[] = array('style' => 'details', 'value' => $engine->getOutput($markup_objects[$key], 'default'), 'show' => false); if (empty($hidden['details'])) { $hidden['details'] = 0; } $hidden['details']++; } } } $show_string = $this->renderShowString($hidden); $view = new DifferentialResultsTableView(); $view->setRows($rows); $view->setShowMoreString($show_string); return $view->render(); }
private function buildRenderedCommentResponse(PhabricatorInlineCommentInterface $inline, $on_right) { $request = $this->getRequest(); $user = $request->getUser(); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); $engine->process(); $phids = array($user->getPHID()); $handles = $this->loadViewerHandles($phids); $object_owner_phid = $this->loadObjectOwnerPHID($inline); $view = id(new PHUIDiffInlineCommentDetailView())->setUser($user)->setInlineComment($inline)->setIsOnRight($on_right)->setMarkupEngine($engine)->setHandles($handles)->setEditable(true)->setCanMarkDone(false)->setObjectOwnerPHID($object_owner_phid); $view = $this->buildScaffoldForView($view); return id(new AphrontAjaxResponse())->setContent(array('inlineCommentID' => $inline->getID(), 'markup' => $view->render())); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $comments = $request->getStr('comments'); $task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($this->id))->executeOne(); if (!$task) { return new Aphront404Response(); } id(new PhabricatorDraft())->setAuthorPHID($user->getPHID())->setDraftKey($task->getPHID())->setDraft($comments)->replaceOrDelete(); $action = $request->getStr('action'); $transaction = new ManiphestTransaction(); $transaction->setAuthorPHID($user->getPHID()); $transaction->setTransactionType($action); // This should really be split into a separate transaction, but it should // all come out in the wash once we fully move to modern stuff. $transaction->attachComment(id(new ManiphestTransactionComment())->setContent($comments)); $value = $request->getStr('value'); // grab phids for handles and set transaction values based on action and // value (empty or control-specific format) coming in from the wire switch ($action) { case ManiphestTransaction::TYPE_PRIORITY: $transaction->setOldValue($task->getPriority()); $transaction->setNewValue($value); break; case ManiphestTransaction::TYPE_OWNER: if ($value) { $value = current(json_decode($value)); $phids = array($value); } else { $phids = array(); } $transaction->setNewValue($value); break; case ManiphestTransaction::TYPE_CCS: if ($value) { $value = json_decode($value); } if (!$value) { $value = array(); } $phids = $value; foreach ($task->getCCPHIDs() as $cc_phid) { $phids[] = $cc_phid; $value[] = $cc_phid; } $transaction->setOldValue($task->getCCPHIDs()); $transaction->setNewValue($value); break; case ManiphestTransaction::TYPE_PROJECTS: if ($value) { $value = json_decode($value); } if (!$value) { $value = array(); } $phids = array(); $value = array_fuse($value); foreach ($value as $project_phid) { $phids[] = $project_phid; $value[$project_phid] = array('dst' => $project_phid); } $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transaction->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setOldValue(array())->setNewValue($value); break; case ManiphestTransaction::TYPE_STATUS: $phids = array(); $transaction->setOldValue($task->getStatus()); $transaction->setNewValue($value); break; default: $phids = array(); $transaction->setNewValue($value); break; } $phids[] = $user->getPHID(); $handles = $this->loadViewerHandles($phids); $transactions = array(); $transactions[] = $transaction; $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); if ($transaction->hasComment()) { $engine->addObject($transaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } $engine->process(); $transaction->setHandles($handles); $view = id(new PhabricatorApplicationTransactionView())->setUser($user)->setTransactions($transactions)->setIsPreview(true); return id(new AphrontAjaxResponse())->setContent((string) phutil_implode_html('', $view->buildEvents())); }
private function buildDisplayRows(array $lines, array $blame_list, array $blame_commits, $show_color, $show_blame) { $request = $this->getRequest(); $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $revision_map = array(); $revisions = array(); if ($blame_commits) { $commit_map = mpull($blame_commits, 'getCommitIdentifier', 'getPHID'); $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(array_keys($commit_map)); if ($revision_ids) { $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute(); $revisions = mpull($revisions, null, 'getID'); } foreach ($revision_ids as $commit_phid => $revision_id) { $revision_map[$commit_map[$commit_phid]] = $revision_id; } } $phids = array(); foreach ($blame_commits as $commit) { $author_phid = $commit->getAuthorPHID(); if ($author_phid === null) { continue; } $phids[$author_phid] = $author_phid; } foreach ($revisions as $revision) { $author_phid = $revision->getAuthorPHID(); if ($author_phid === null) { continue; } $phids[$author_phid] = $author_phid; } $handles = $viewer->loadHandles($phids); $colors = array(); if ($blame_commits) { $epochs = array(); foreach ($blame_commits as $identifier => $commit) { $epochs[$identifier] = $commit->getEpoch(); } $epoch_list = array_filter($epochs); $epoch_list = array_unique($epoch_list); $epoch_list = array_values($epoch_list); $epoch_min = min($epoch_list); $epoch_max = max($epoch_list); $epoch_range = $epoch_max - $epoch_min + 1; foreach ($blame_commits as $identifier => $commit) { $epoch = $epochs[$identifier]; if (!$epoch) { $color = '#ffffdd'; // Warning color, missing data. } else { $color_ratio = ($epoch - $epoch_min) / $epoch_range; $color_value = 0xe6 * (1.0 - $color_ratio); $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value); } $colors[$identifier] = $color; } } $display = array(); $last_identifier = null; $last_color = null; foreach ($lines as $line_index => $line) { $color = '#f6f6f6'; $duplicate = false; if (isset($blame_list[$line_index])) { $identifier = $blame_list[$line_index]; if (isset($colors[$identifier])) { $color = $colors[$identifier]; } if ($identifier === $last_identifier) { $duplicate = true; } else { $last_identifier = $identifier; } } $display[$line_index] = array('data' => $line, 'target' => false, 'highlighted' => false, 'color' => $color, 'duplicate' => $duplicate); } $line_arr = array(); $line_str = $drequest->getLine(); $ranges = explode(',', $line_str); foreach ($ranges as $range) { if (strpos($range, '-') !== false) { list($min, $max) = explode('-', $range, 2); $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max)); } else { if (strlen($range)) { $line_arr[] = array('min' => $range, 'max' => $range); } } } // Mark the first highlighted line as the target line. if ($line_arr) { $target_line = $line_arr[0]['min']; if (isset($display[$target_line - 1])) { $display[$target_line - 1]['target'] = true; } } // Mark all other highlighted lines as highlighted. foreach ($line_arr as $range) { for ($ii = $range['min']; $ii <= $range['max']; $ii++) { if (isset($display[$ii - 1])) { $display[$ii - 1]['highlighted'] = true; } } } $engine = null; $inlines = array(); if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) { $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($this->lintMessages as $message) { $inline = id(new PhabricatorAuditInlineComment())->setSyntheticAuthor(ArcanistLintSeverity::getStringForSeverity($message['severity']) . ' ' . $message['code'] . ' (' . $message['name'] . ')')->setLineNumber($message['line'])->setContent($message['description']); $inlines[$message['line']][] = $inline; $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); require_celerity_resource('differential-changeset-view-css'); } $rows = $this->renderInlines(idx($inlines, 0, array()), $show_blame, (bool) $this->coverage, $engine); // NOTE: We're doing this manually because rendering is otherwise // dominated by URI generation for very large files. $line_base = (string) $drequest->generateURI(array('action' => 'browse', 'stable' => true)); require_celerity_resource('aphront-tooltip-css'); Javelin::initBehavior('phabricator-oncopy'); Javelin::initBehavior('phabricator-tooltips'); Javelin::initBehavior('phabricator-line-linker'); // Render these once, since they tend to get repeated many times in large // blame outputs. $commit_links = $this->renderCommitLinks($blame_commits, $handles); $revision_links = $this->renderRevisionLinks($revisions, $handles); $skip_text = pht('Skip Past This Commit'); foreach ($display as $line_index => $line) { $row = array(); $line_number = $line_index + 1; $line_href = $line_base . '$' . $line_number; if (isset($blame_list[$line_index])) { $identifier = $blame_list[$line_index]; } else { $identifier = null; } $revision_link = null; $commit_link = null; $before_link = null; $style = 'background: ' . $line['color'] . ';'; if ($identifier && !$line['duplicate']) { if (isset($commit_links[$identifier])) { $commit_link = $commit_links[$identifier]; } if (isset($revision_map[$identifier])) { $revision_id = $revision_map[$identifier]; if (isset($revision_links[$revision_id])) { $revision_link = $revision_links[$revision_id]; } } $skip_href = $line_href . '?before=' . $identifier . '&view=blame'; $before_link = javelin_tag('a', array('href' => $skip_href, 'sigil' => 'has-tooltip', 'meta' => array('tip' => $skip_text, 'align' => 'E', 'size' => 300)), "«"); } $row[] = phutil_tag('th', array('class' => 'diffusion-blame-link'), $before_link); $object_links = array(); $object_links[] = $commit_link; if ($revision_link) { $object_links[] = phutil_tag('span', array(), '/'); $object_links[] = $revision_link; } $row[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links); $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line_number); $row[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link); if ($line['target']) { Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target')); $anchor_text = phutil_tag('a', array('id' => 'scroll_target'), ''); } else { $anchor_text = null; } $row[] = phutil_tag('td', array(), array($anchor_text, "", phutil_safe_html(str_replace("\t", ' ', $line['data'])))); if ($this->coverage) { require_celerity_resource('differential-changeset-view-css'); $cov_index = $line_index; if (isset($this->coverage[$cov_index])) { $cov_class = $this->coverage[$cov_index]; } else { $cov_class = 'N'; } $row[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), ''); } $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $row); $cur_inlines = $this->renderInlines(idx($inlines, $line_number, array()), $show_blame, $this->coverage, $engine); foreach ($cur_inlines as $cur_inline) { $rows[] = $cur_inline; } } return $rows; }
private function buildDisplayRows(array $text_list, array $rev_list, array $blame_dict, $needs_blame, DiffusionRequest $drequest, $show_blame, $show_color) { $handles = array(); if ($blame_dict) { $epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch'); $epoch_min = min($epoch_list); $epoch_max = max($epoch_list); $epoch_range = $epoch_max - $epoch_min + 1; $author_phids = ipull(ifilter($blame_dict, 'authorPHID'), 'authorPHID'); $handles = $this->loadViewerHandles($author_phids); } $line_arr = array(); $line_str = $drequest->getLine(); $ranges = explode(',', $line_str); foreach ($ranges as $range) { if (strpos($range, '-') !== false) { list($min, $max) = explode('-', $range, 2); $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max)); } else { if (strlen($range)) { $line_arr[] = array('min' => $range, 'max' => $range); } } } $display = array(); $line_number = 1; $last_rev = null; $color = null; foreach ($text_list as $k => $line) { $display_line = array('epoch' => null, 'commit' => null, 'author' => null, 'target' => null, 'highlighted' => null, 'line' => $line_number, 'data' => $line); if ($show_blame) { // If the line's rev is same as the line above, show empty content // with same color; otherwise generate blame info. The newer a change // is, the more saturated the color. $rev = idx($rev_list, $k, $last_rev); if ($last_rev == $rev) { $display_line['color'] = $color; } else { $blame = $blame_dict[$rev]; if (!isset($blame['epoch'])) { $color = '#ffd'; // Render as warning. } else { $color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range; $color_value = 0xe6 * (1.0 - $color_ratio); $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value); } $display_line['epoch'] = idx($blame, 'epoch'); $display_line['color'] = $color; $display_line['commit'] = $rev; $author_phid = idx($blame, 'authorPHID'); if ($author_phid && $handles[$author_phid]) { $author_link = $handles[$author_phid]->renderLink(); } else { $author_link = $blame['author']; } $display_line['author'] = $author_link; $last_rev = $rev; } } if ($line_arr) { if ($line_number == $line_arr[0]['min']) { $display_line['target'] = true; } foreach ($line_arr as $range) { if ($line_number >= $range['min'] && $line_number <= $range['max']) { $display_line['highlighted'] = true; } } } $display[] = $display_line; ++$line_number; } $request = $this->getRequest(); $viewer = $request->getUser(); $commits = array_filter(ipull($display, 'commit')); if ($commits) { $commits = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($drequest->getRepository())->withIdentifiers($commits)->execute(); $commits = mpull($commits, null, 'getCommitIdentifier'); } $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(mpull($commits, 'getPHID')); $revisions = array(); if ($revision_ids) { $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute(); } $phids = array(); foreach ($commits as $commit) { if ($commit->getAuthorPHID()) { $phids[] = $commit->getAuthorPHID(); } } foreach ($revisions as $revision) { if ($revision->getAuthorPHID()) { $phids[] = $revision->getAuthorPHID(); } } $handles = $this->loadViewerHandles($phids); Javelin::initBehavior('phabricator-oncopy', array()); $engine = null; $inlines = array(); if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) { $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($this->lintMessages as $message) { $inline = id(new PhabricatorAuditInlineComment())->setSyntheticAuthor(ArcanistLintSeverity::getStringForSeverity($message['severity']) . ' ' . $message['code'] . ' (' . $message['name'] . ')')->setLineNumber($message['line'])->setContent($message['description']); $inlines[$message['line']][] = $inline; $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); require_celerity_resource('differential-changeset-view-css'); } $rows = $this->renderInlines(idx($inlines, 0, array()), $show_blame, (bool) $this->coverage, $engine); foreach ($display as $line) { $line_href = $drequest->generateURI(array('action' => 'browse', 'line' => $line['line'], 'stable' => true)); $blame = array(); $style = null; if (array_key_exists('color', $line)) { if ($line['color']) { $style = 'background: ' . $line['color'] . ';'; } $before_link = null; $commit_link = null; $revision_link = null; if (idx($line, 'commit')) { $commit = $line['commit']; if (idx($commits, $commit)) { $tooltip = $this->renderCommitTooltip($commits[$commit], $handles, $line['author']); } else { $tooltip = null; } Javelin::initBehavior('phabricator-tooltips', array()); require_celerity_resource('aphront-tooltip-css'); $commit_link = javelin_tag('a', array('href' => $drequest->generateURI(array('action' => 'commit', 'commit' => $line['commit'])), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(9)->setTerminator('')->truncateString($line['commit'])); $revision_id = null; if (idx($commits, $commit)) { $revision_id = idx($revision_ids, $commits[$commit]->getPHID()); } if ($revision_id) { $revision = idx($revisions, $revision_id); if ($revision) { $tooltip = $this->renderRevisionTooltip($revision, $handles); $revision_link = javelin_tag('a', array('href' => '/D' . $revision->getID(), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), 'D' . $revision->getID()); } } $uri = $line_href->alter('before', $commit); $before_link = javelin_tag('a', array('href' => $uri->setQueryParam('view', 'blame'), 'sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Skip Past This Commit'), 'align' => 'E', 'size' => 300)), "«"); } $blame[] = phutil_tag('th', array('class' => 'diffusion-blame-link'), $before_link); $object_links = array(); $object_links[] = $commit_link; if ($revision_link) { $object_links[] = phutil_tag('span', array(), '/'); $object_links[] = $revision_link; } $blame[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links); } $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line['line']); $blame[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link); Javelin::initBehavior('phabricator-line-linker'); if ($line['target']) { Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target')); $anchor_text = phutil_tag('a', array('id' => 'scroll_target'), ''); } else { $anchor_text = null; } $blame[] = phutil_tag('td', array(), array($anchor_text, "", phutil_safe_html(str_replace("\t", ' ', $line['data'])))); if ($this->coverage) { require_celerity_resource('differential-changeset-view-css'); $cov_index = $line['line'] - 1; if (isset($this->coverage[$cov_index])) { $cov_class = $this->coverage[$cov_index]; } else { $cov_class = 'N'; } $blame[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), ''); } $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $blame); $cur_inlines = $this->renderInlines(idx($inlines, $line['line'], array()), $show_blame, $this->coverage, $engine); foreach ($cur_inlines as $cur_inline) { $rows[] = $cur_inline; } } return $rows; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($this->id))->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($workflow))->executeOne(); } $transactions = id(new ManiphestTransactionQuery())->setViewer($user)->withObjectPHIDs(array($task->getPHID()))->needComments(true)->execute(); $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($user)->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK; $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock)); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), 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); $this->loadHandles($phids); $handles = $this->getLoadedHandles(); $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag('a', array('href' => '/maniphest/task/create/?parent=' . $parent_task->getID(), 'class' => 'green button'), pht('Create Another Subtask'))); $context_bar->appendChild(hsprintf('Created a subtask of <strong>%s</strong>', $this->getHandle($parent_task->getPHID())->renderLink())); } else { if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag('label', array(), 'Create Another')); $context_bar->addButton(phutil_tag('a', array('href' => '/maniphest/task/create/?template=' . $task->getID(), 'class' => 'green button'), pht('Similar Task'))); $context_bar->addButton(phutil_tag('a', array('href' => '/maniphest/task/create/', 'class' => 'green button'), pht('Empty Task'))); $context_bar->appendChild(pht('New task created.')); } } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); foreach ($transactions as $modern_xaction) { if ($modern_xaction->getComment()) { $engine->addObject($modern_xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); $transaction_types = array(PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), ManiphestTransaction::TYPE_CCS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), ManiphestTransaction::TYPE_PROJECTS => pht('Associate Projects')); // Remove actions the user doesn't have permission to take. $requires = array(ManiphestTransaction::TYPE_OWNER => ManiphestEditAssignCapability::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestEditPriorityCapability::CAPABILITY, ManiphestTransaction::TYPE_PROJECTS => ManiphestEditProjectsCapability::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestEditStatusCapability::CAPABILITY); foreach ($transaction_types as $type => $name) { if (isset($requires[$type])) { if (!$this->hasApplicationCapability($requires[$type])) { unset($transaction_types[$type]); } } } // Don't show an option to change to the current status, or to change to // the duplicate status explicitly. unset($resolution_types[$task->getStatus()]); unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]); // Don't show owner/priority changes for closed tasks, as they don't make // much sense. if ($task->isClosed()) { unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransaction::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; } $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setWorkflow(true)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Assign To'))->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('CCs'))->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('File'))->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Comments'))->setName('comments')->setValue($draft_text)->setID('transaction-comments')->setUser($user))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit'))); $control_map = array(ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', ManiphestTransaction::TYPE_CCS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', ManiphestTransaction::TYPE_PROJECTS => 'projects'); $projects_source = new PhabricatorProjectDatasource(); $users_source = new PhabricatorPeopleDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $tokenizer_map = array(ManiphestTransaction::TYPE_PROJECTS => array('id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), ManiphestTransaction::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText()), ManiphestTransaction::TYPE_CCS => array('id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText())); // TODO: Initializing these behaviors for logged out users fatals things. if ($user->isLoggedIn()) { 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)); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In'); $preview_panel = phutil_tag_div('aphront-panel-preview', phutil_tag('div', array('id' => 'transaction-preview'), phutil_tag_div('aphront-panel-preview-loading-text', pht('Loading preview...')))); $timeline = id(new PhabricatorApplicationTransactionView())->setUser($user)->setObjectPHID($task->getPHID())->setTransactions($transactions)->setMarkupEngine($engine); $object_name = 'T' . $task->getID(); $actions = $this->buildActionView($task); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($object_name, '/' . $object_name)->setActionList($actions); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView($task, $field_list, $edges, $actions); $description = $this->buildDescriptionView($task, $engine); if (!$user->isLoggedIn()) { // TODO: Eventually, everything should run through this. For now, we're // only using it to get a consistent "Login to Comment" button. $comment_box = id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI()); $preview_panel = null; } else { $comment_box = id(new PHUIObjectBoxView())->setFlush(true)->setHeaderText($comment_header)->appendChild($comment_form); $timeline->setQuoteTargetID('transaction-comments'); $timeline->setQuoteRef($object_name); } $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); if ($description) { $object_box->addPropertyList($description); } return $this->buildApplicationPage(array($crumbs, $context_bar, $object_box, $timeline, $comment_box, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID()))); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $rendering_reference = $request->getStr('ref'); $parts = explode('/', $rendering_reference); if (count($parts) == 2) { list($id, $vs) = $parts; } else { $id = $parts[0]; $vs = 0; } $id = (int) $id; $vs = (int) $vs; $load_ids = array($id); if ($vs && $vs != -1) { $load_ids[] = $vs; } $changesets = id(new DifferentialChangesetQuery())->setViewer($viewer)->withIDs($load_ids)->needHunks(true)->execute(); $changesets = mpull($changesets, null, 'getID'); $changeset = idx($changesets, $id); if (!$changeset) { return new Aphront404Response(); } $vs_changeset = null; if ($vs && $vs != -1) { $vs_changeset = idx($changesets, $vs); if (!$vs_changeset) { return new Aphront404Response(); } } $view = $request->getStr('view'); if ($view) { $phid = idx($changeset->getMetadata(), "{$view}:binary-phid"); if ($phid) { return id(new AphrontRedirectResponse())->setURI("/file/info/{$phid}/"); } switch ($view) { case 'new': return $this->buildRawFileResponse($changeset, $is_new = true); case 'old': if ($vs_changeset) { return $this->buildRawFileResponse($vs_changeset, $is_new = true); } return $this->buildRawFileResponse($changeset, $is_new = false); default: return new Aphront400Response(); } } $old = array(); $new = array(); if (!$vs) { $right = $changeset; $left = null; $right_source = $right->getID(); $right_new = true; $left_source = $right->getID(); $left_new = false; $render_cache_key = $right->getID(); $old[] = $changeset; $new[] = $changeset; } else { if ($vs == -1) { $right = null; $left = $changeset; $right_source = $left->getID(); $right_new = false; $left_source = $left->getID(); $left_new = true; $render_cache_key = null; $old[] = $changeset; $new[] = $changeset; } else { $right = $changeset; $left = $vs_changeset; $right_source = $right->getID(); $right_new = true; $left_source = $left->getID(); $left_new = true; $render_cache_key = null; $new[] = $left; $new[] = $right; } } if ($left) { $left_data = $left->makeNewFile(); if ($right) { $right_data = $right->makeNewFile(); } else { $right_data = $left->makeOldFile(); } $engine = new PhabricatorDifferenceEngine(); $synthetic = $engine->generateChangesetFromFileContent($left_data, $right_data); $choice = clone nonempty($left, $right); $choice->attachHunks($synthetic->getHunks()); $changeset = $choice; } if ($left_new || $right_new) { $diff_map = array(); if ($left) { $diff_map[] = $left->getDiff(); } if ($right) { $diff_map[] = $right->getDiff(); } $diff_map = mpull($diff_map, null, 'getPHID'); $buildables = id(new HarbormasterBuildableQuery())->setViewer($viewer)->withBuildablePHIDs(array_keys($diff_map))->withManualBuildables(false)->needBuilds(true)->needTargets(true)->execute(); $buildables = mpull($buildables, null, 'getBuildablePHID'); foreach ($diff_map as $diff_phid => $changeset_diff) { $changeset_diff->attachBuildable(idx($buildables, $diff_phid)); } } $coverage = null; if ($right_new) { $coverage = $this->loadCoverage($right); } $spec = $request->getStr('range'); list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec); $parser = id(new DifferentialChangesetParser())->setCoverage($coverage)->setChangeset($changeset)->setRenderingReference($rendering_reference)->setRenderCacheKey($render_cache_key)->setRightSideCommentMapping($right_source, $right_new)->setLeftSideCommentMapping($left_source, $left_new); $parser->readParametersFromRequest($request); if ($left && $right) { $parser->setOriginals($left, $right); } $diff = $changeset->getDiff(); $revision_id = $diff->getRevisionID(); $can_mark = false; $object_owner_phid = null; $revision = null; if ($revision_id) { $revision = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($revision_id))->executeOne(); if ($revision) { $can_mark = $revision->getAuthorPHID() == $viewer->getPHID(); $object_owner_phid = $revision->getAuthorPHID(); } } // Load both left-side and right-side inline comments. if ($revision) { $query = id(new DifferentialInlineCommentQuery())->setViewer($viewer)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); } else { $inlines = array(); } if ($left_new) { $inlines = array_merge($inlines, $this->buildLintInlineComments($left)); } if ($right_new) { $inlines = array_merge($inlines, $this->buildLintInlineComments($right)); } $phids = array(); foreach ($inlines as $inline) { $parser->parseInlineComment($inline); if ($inline->getAuthorPHID()) { $phids[$inline->getAuthorPHID()] = true; } } $phids = array_keys($phids); $handles = $this->loadViewerHandles($phids); $parser->setHandles($handles); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($inlines as $inline) { $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); $parser->setUser($viewer)->setMarkupEngine($engine)->setShowEditAndReplyLinks(true)->setCanMarkDone($can_mark)->setObjectOwnerPHID($object_owner_phid)->setRange($range_s, $range_e)->setMask($mask); if ($request->isAjax()) { // NOTE: We must render the changeset before we render coverage // information, since it builds some caches. $rendered_changeset = $parser->renderChangeset(); $mcov = $parser->renderModifiedCoverage(); $coverage_data = array('differential-mcoverage-' . md5($changeset->getFilename()) => $mcov); return id(new PhabricatorChangesetResponse())->setRenderedChangeset($rendered_changeset)->setCoverage($coverage_data)->setUndoTemplates($parser->getRenderer()->renderUndoTemplates()); } $detail = id(new DifferentialChangesetListView())->setUser($this->getViewer())->setChangesets(array($changeset))->setVisibleChangesets(array($changeset))->setRenderingReferences(array($rendering_reference))->setRenderURI('/differential/changeset/')->setDiff($diff)->setTitle(pht('Standalone View'))->setParser($parser); if ($revision_id) { $detail->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision_id . '/'); } $crumbs = $this->buildApplicationCrumbs(); if ($revision_id) { $crumbs->addTextCrumb('D' . $revision_id, '/D' . $revision_id); } $diff_id = $diff->getID(); if ($diff_id) { $crumbs->addTextCrumb(pht('Diff %d', $diff_id), $this->getApplicationURI('diff/' . $diff_id)); } $crumbs->addTextCrumb($changeset->getDisplayFilename()); return $this->buildApplicationPage(array($crumbs, $detail), array('title' => pht('Changeset View'), 'device' => false)); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $options = PhabricatorApplicationConfigOptions::loadAllOptions(); if (empty($options[$this->key])) { $ancient = PhabricatorExtraConfigSetupCheck::getAncientConfig(); if (isset($ancient[$this->key])) { $desc = pht("This configuration has been removed. You can safely delete " . "it.\n\n%s", $ancient[$this->key]); } else { $desc = pht('This configuration option is unknown. It may be misspelled, ' . 'or have existed in a previous version of Phabricator.'); } // This may be a dead config entry, which existed in the past but no // longer exists. Allow it to be edited so it can be reviewed and // deleted. $option = id(new PhabricatorConfigOption())->setKey($this->key)->setType('wild')->setDefault(null)->setDescription($desc); $group = null; $group_uri = $this->getApplicationURI(); } else { $option = $options[$this->key]; $group = $option->getGroup(); $group_uri = $this->getApplicationURI('group/' . $group->getKey() . '/'); } $issue = $request->getStr('issue'); if ($issue) { // If the user came here from an open setup issue, send them back. $done_uri = $this->getApplicationURI('issue/' . $issue . '/'); } else { $done_uri = $group_uri; } // Check if the config key is already stored in the database. // Grab the value if it is. $config_entry = id(new PhabricatorConfigEntry())->loadOneWhere('configKey = %s AND namespace = %s', $this->key, 'default'); if (!$config_entry) { $config_entry = id(new PhabricatorConfigEntry())->setConfigKey($this->key)->setNamespace('default')->setIsDeleted(true); $config_entry->setPHID($config_entry->generatePHID()); } $e_value = null; $errors = array(); if ($request->isFormPost() && !$option->getLocked()) { $result = $this->readRequest($option, $request); list($e_value, $value_errors, $display_value, $xaction) = $result; $errors = array_merge($errors, $value_errors); if (!$errors) { $editor = id(new PhabricatorConfigEditor())->setActor($user)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); try { $editor->applyTransactions($config_entry, array($xaction)); return id(new AphrontRedirectResponse())->setURI($done_uri); } catch (PhabricatorConfigValidationException $ex) { $e_value = pht('Invalid'); $errors[] = $ex->getMessage(); } } } else { if ($config_entry->getIsDeleted()) { $display_value = null; } else { $display_value = $this->getDisplayValue($option, $config_entry, $config_entry->getValue()); } } $form = new AphrontFormView(); $error_view = null; if ($errors) { $error_view = id(new PHUIInfoView())->setErrors($errors); } else { if ($option->getHidden()) { $msg = pht('This configuration is hidden and can not be edited or viewed from ' . 'the web interface.'); $error_view = id(new PHUIInfoView())->setTitle(pht('Configuration Hidden'))->setSeverity(PHUIInfoView::SEVERITY_WARNING)->appendChild(phutil_tag('p', array(), $msg)); } else { if ($option->getLocked()) { $msg = $option->getLockedMessage(); $error_view = id(new PHUIInfoView())->setTitle(pht('Configuration Locked'))->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->appendChild(phutil_tag('p', array(), $msg)); } } } if ($option->getHidden()) { $control = null; } else { $control = $this->renderControl($option, $display_value, $e_value); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($option, 'description'); $engine->process(); $description = phutil_tag('div', array('class' => 'phabricator-remarkup'), $engine->getOutput($option, 'description')); $form->setUser($user)->addHiddenInput('issue', $request->getStr('issue'))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Description'))->setValue($description)); if ($group) { $extra = $group->renderContextualDescription($option, $request); if ($extra !== null) { $form->appendChild(id(new AphrontFormMarkupControl())->setValue($extra)); } } $form->appendChild($control); $submit_control = id(new AphrontFormSubmitControl())->addCancelButton($done_uri); if (!$option->getLocked()) { $submit_control->setValue(pht('Save Config Entry')); } $form->appendChild($submit_control); $examples = $this->renderExamples($option); if ($examples) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Examples'))->setValue($examples)); } if (!$option->getHidden()) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Default'))->setValue($this->renderDefaults($option, $config_entry))); } $title = pht('Edit %s', $this->key); $short = pht('Edit'); $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setForm($form); if ($error_view) { $form_box->setInfoView($error_view); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Config'), $this->getApplicationURI()); if ($group) { $crumbs->addTextCrumb($group->getName(), $group_uri); } $crumbs->addTextCrumb($this->key, '/config/edit/' . $this->key); $timeline = $this->buildTransactionTimeline($config_entry, new PhabricatorConfigTransactionQuery()); $timeline->setShouldTerminate(true); return $this->buildApplicationPage(array($crumbs, $form_box, $timeline), array('title' => $title)); }
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 handleRequest(AphrontRequest $request) { $response = $this->loadDiffusionContext(); if ($response) { return $response; } $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); if (!$request->isAjax()) { // This request came out of the dropdown menu, either "View Standalone" // or "View Raw File". $view = $request->getStr('view'); if ($view == 'r') { $uri = $drequest->generateURI(array('action' => 'browse', 'params' => array('view' => 'raw'))); } else { $uri = $drequest->generateURI(array('action' => 'change')); } return id(new AphrontRedirectResponse())->setURI($uri); } $data = $this->callConduitWithDiffusionRequest('diffusion.diffquery', array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath())); $drequest->updateSymbolicCommit($data['effectiveCommit']); $raw_changes = ArcanistDiffChange::newFromConduit($data['changes']); $diff = DifferentialDiff::newEphemeralFromRawChanges($raw_changes); $changesets = $diff->getChangesets(); $changeset = reset($changesets); if (!$changeset) { return new Aphront404Response(); } $parser = new DifferentialChangesetParser(); $parser->setUser($viewer); $parser->setChangeset($changeset); $parser->setRenderingReference($drequest->generateURI(array('action' => 'rendering-ref'))); $parser->readParametersFromRequest($request); $coverage = $drequest->loadCoverage(); if ($coverage) { $parser->setCoverage($coverage); } $commit = $drequest->loadCommit(); $pquery = new DiffusionPathIDQuery(array($changeset->getFilename())); $ids = $pquery->loadPathIDs(); $path_id = $ids[$changeset->getFilename()]; $parser->setLeftSideCommentMapping($path_id, false); $parser->setRightSideCommentMapping($path_id, true); $parser->setCanMarkDone($commit->getAuthorPHID() && $viewer->getPHID() == $commit->getAuthorPHID()); $parser->setObjectOwnerPHID($commit->getAuthorPHID()); $parser->setWhitespaceMode(DifferentialChangesetParser::WHITESPACE_SHOW_ALL); $inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments($viewer, $commit->getPHID(), $path_id); if ($inlines) { foreach ($inlines as $inline) { $parser->parseInlineComment($inline); } $phids = mpull($inlines, 'getAuthorPHID'); $handles = $this->loadViewerHandles($phids); $parser->setHandles($handles); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($inlines as $inline) { $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); $parser->setMarkupEngine($engine); $spec = $request->getStr('range'); list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec); $parser->setRange($range_s, $range_e); $parser->setMask($mask); return id(new PhabricatorChangesetResponse())->setRenderedChangeset($parser->renderChangeset())->setUndoTemplates($parser->getRenderer()->renderUndoTemplates()); }
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()))); }
private function buildRenderedCommentResponse(PhabricatorInlineCommentInterface $inline, $on_right) { $request = $this->getRequest(); $user = $request->getUser(); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); $engine->process(); $phids = array($user->getPHID()); $handles = $this->loadViewerHandles($phids); $view = new DifferentialInlineCommentView(); $view->setInlineComment($inline); $view->setOnRight($on_right); $view->setBuildScaffolding(true); $view->setMarkupEngine($engine); $view->setHandles($handles); $view->setEditable(true); return id(new AphrontAjaxResponse())->setContent(array('inlineCommentID' => $inline->getID(), 'markup' => $view->render())); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $key = $request->getURIData('key'); $options = PhabricatorApplicationConfigOptions::loadAllOptions(); if (empty($options[$key])) { $ancient = PhabricatorExtraConfigSetupCheck::getAncientConfig(); if (isset($ancient[$key])) { $desc = pht("This configuration has been removed. You can safely delete " . "it.\n\n%s", $ancient[$key]); } else { $desc = pht('This configuration option is unknown. It may be misspelled, ' . 'or have existed in a previous version of Phabricator.'); } // This may be a dead config entry, which existed in the past but no // longer exists. Allow it to be edited so it can be reviewed and // deleted. $option = id(new PhabricatorConfigOption())->setKey($key)->setType('wild')->setDefault(null)->setDescription($desc); $group = null; $group_uri = $this->getApplicationURI(); } else { $option = $options[$key]; $group = $option->getGroup(); $group_uri = $this->getApplicationURI('group/' . $group->getKey() . '/'); } $issue = $request->getStr('issue'); if ($issue) { // If the user came here from an open setup issue, send them back. $done_uri = $this->getApplicationURI('issue/' . $issue . '/'); } else { $done_uri = $group_uri; } // Check if the config key is already stored in the database. // Grab the value if it is. $config_entry = id(new PhabricatorConfigEntry())->loadOneWhere('configKey = %s AND namespace = %s', $key, 'default'); if (!$config_entry) { $config_entry = id(new PhabricatorConfigEntry())->setConfigKey($key)->setNamespace('default')->setIsDeleted(true); $config_entry->setPHID($config_entry->generatePHID()); } $e_value = null; $errors = array(); if ($request->isFormPost() && !$option->getLocked()) { $result = $this->readRequest($option, $request); list($e_value, $value_errors, $display_value, $xaction) = $result; $errors = array_merge($errors, $value_errors); if (!$errors) { $editor = id(new PhabricatorConfigEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); try { $editor->applyTransactions($config_entry, array($xaction)); return id(new AphrontRedirectResponse())->setURI($done_uri); } catch (PhabricatorConfigValidationException $ex) { $e_value = pht('Invalid'); $errors[] = $ex->getMessage(); } } } else { if ($config_entry->getIsDeleted()) { $display_value = null; } else { $display_value = $this->getDisplayValue($option, $config_entry, $config_entry->getValue()); } } $form = id(new AphrontFormView())->setEncType('multipart/form-data'); $error_view = null; if ($errors) { $error_view = id(new PHUIInfoView())->setErrors($errors); } $status_items = array(); if ($option->getHidden()) { $message = pht('This configuration is hidden and can not be edited or viewed from ' . 'the web interface.'); $status_items[] = id(new PHUIStatusItemView())->setIcon('fa-eye-slash red')->setTarget(phutil_tag('strong', array(), pht('Configuration Hidden')))->setNote($message); } else { if ($option->getLocked()) { $message = $option->getLockedMessage(); $status_items[] = id(new PHUIStatusItemView())->setIcon('fa-lock red')->setTarget(phutil_tag('strong', array(), pht('Configuration Locked')))->setNote($message); } } if ($status_items) { $doc_href = PhabricatorEnv::getDoclink('Configuration Guide: Locked and Hidden Configuration'); $doc_link = phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Configuration Guide: Locked and Hidden Configuration')); $status_items[] = id(new PHUIStatusItemView())->setIcon('fa-book')->setTarget(phutil_tag('strong', array(), pht('Learn More')))->setNote($doc_link); } if ($option->getHidden() || $option->getLocked()) { $controls = array(); } else { $controls = $this->renderControls($option, $display_value, $e_value); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); $engine->addObject($option, 'description'); $engine->process(); $description = phutil_tag('div', array('class' => 'phabricator-remarkup'), $engine->getOutput($option, 'description')); $form->setUser($viewer)->addHiddenInput('issue', $request->getStr('issue')); if ($status_items) { $status_view = id(new PHUIStatusListView()); foreach ($status_items as $status_item) { $status_view->addItem($status_item); } $form->appendControl(id(new AphrontFormMarkupControl())->setValue($status_view)); } $description = $option->getDescription(); if (strlen($description)) { $description_view = new PHUIRemarkupView($viewer, $description); $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Description'))->setValue($description_view)); } if ($group) { $extra = $group->renderContextualDescription($option, $request); if ($extra !== null) { $form->appendChild(id(new AphrontFormMarkupControl())->setValue($extra)); } } foreach ($controls as $control) { $form->appendControl($control); } if (!$option->getLocked()) { $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($done_uri)->setValue(pht('Save Config Entry'))); } if (!$option->getHidden()) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Current Configuration'))->setValue($this->renderDefaults($option, $config_entry))); } $examples = $this->renderExamples($option); if ($examples) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Examples'))->setValue($examples)); } $title = pht('Edit Option: %s', $key); $header_icon = 'fa-pencil'; $short = pht('Edit'); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Config Option'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); if ($error_view) { $form_box->setInfoView($error_view); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Config'), $this->getApplicationURI()); if ($group) { $crumbs->addTextCrumb($group->getName(), $group_uri); } $crumbs->addTextCrumb($key, '/config/edit/' . $key); $crumbs->setBorder(true); $timeline = $this->buildTransactionTimeline($config_entry, new PhabricatorConfigTransactionQuery()); $timeline->setShouldTerminate(true); $header = id(new PHUIHeaderView())->setHeader($title)->setHeaderIcon($header_icon); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($form_box); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $comments = $request->getStr('comments'); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if (!$draft) { $draft = new PhabricatorDraft(); $draft->setAuthorPHID($user->getPHID()); $draft->setDraftKey($task->getPHID()); } $draft->setDraft($comments); $draft->save(); $action = $request->getStr('action'); $transaction = new ManiphestTransaction(); $transaction->setAuthorPHID($user->getPHID()); $transaction->setComments($comments); $transaction->setTransactionType($action); $value = $request->getStr('value'); // grab phids for handles and set transaction values based on action and // value (empty or control-specific format) coming in from the wire switch ($action) { case ManiphestTransactionType::TYPE_PRIORITY: $transaction->setOldValue($task->getPriority()); $transaction->setNewValue($value); break; case ManiphestTransactionType::TYPE_OWNER: if ($value) { $value = current(json_decode($value)); $phids = array($value); } else { $phids = array(); } $transaction->setNewValue($value); break; case ManiphestTransactionType::TYPE_CCS: if ($value) { $value = json_decode($value); $phids = $value; foreach ($task->getCCPHIDs() as $cc_phid) { $phids[] = $cc_phid; $value[] = $cc_phid; } $transaction->setNewValue($value); } else { $phids = array(); $transaction->setNewValue(array()); } $transaction->setOldValue($task->getCCPHIDs()); break; case ManiphestTransactionType::TYPE_PROJECTS: if ($value) { $value = json_decode($value); $phids = $value; foreach ($task->getProjectPHIDs() as $project_phid) { $phids[] = $project_phid; $value[] = $project_phid; } $transaction->setNewValue($value); } else { $phids = array(); $transaction->setNewValue(array()); } $transaction->setOldValue($task->getProjectPHIDs()); break; default: $phids = array(); $transaction->setNewValue($value); break; } $phids[] = $user->getPHID(); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $transactions = array(); $transactions[] = $transaction; $engine = new PhabricatorMarkupEngine(); $engine->addObject($transaction, ManiphestTransaction::MARKUP_FIELD_BODY); $engine->process(); $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); $transaction_view->setPreview(true); return id(new AphrontAjaxResponse())->setContent($transaction_view->render()); }
protected function buildTransactionTimeline(PhabricatorApplicationTransactionInterface $object, PhabricatorApplicationTransactionQuery $query, PhabricatorMarkupEngine $engine = null, $render_data = array()) { $viewer = $this->getRequest()->getUser(); $xaction = $object->getApplicationTransactionTemplate(); $view = $xaction->getApplicationTransactionViewObject(); $pager = id(new AphrontCursorPagerView())->readFromRequest($this->getRequest())->setURI(new PhutilURI('/transactions/showolder/' . $object->getPHID() . '/')); $xactions = $query->setViewer($viewer)->withObjectPHIDs(array($object->getPHID()))->needComments(true)->executeWithCursorPager($pager); $xactions = array_reverse($xactions); if ($engine) { foreach ($xactions as $xaction) { if ($xaction->getComment()) { $engine->addObject($xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); $view->setMarkupEngine($engine); } $timeline = $view->setUser($viewer)->setObjectPHID($object->getPHID())->setTransactions($xactions)->setPager($pager)->setRenderData($render_data)->setQuoteTargetID($this->getRequest()->getStr('quoteTargetID'))->setQuoteRef($this->getRequest()->getStr('quoteRef')); $object->willRenderTimeline($timeline, $this->getRequest()); return $timeline; }
/** * Given @{class:PhabricatorFeedStoryData} rows, load them into objects and * construct appropriate @{class:PhabricatorFeedStory} wrappers for each * data row. * * @param list<dict> List of @{class:PhabricatorFeedStoryData} rows from the * database. * @return list<PhabricatorFeedStory> List of @{class:PhabricatorFeedStory} * objects. * @task load */ public static function loadAllFromRows(array $rows, PhabricatorUser $viewer) { $stories = array(); $data = id(new PhabricatorFeedStoryData())->loadAllFromArray($rows); foreach ($data as $story_data) { $class = $story_data->getStoryType(); try { $ok = class_exists($class) && is_subclass_of($class, __CLASS__); } catch (PhutilMissingSymbolException $ex) { $ok = false; } // If the story type isn't a valid class or isn't a subclass of // PhabricatorFeedStory, decline to load it. if (!$ok) { continue; } $key = $story_data->getChronologicalKey(); $stories[$key] = newv($class, array($story_data)); } $object_phids = array(); $key_phids = array(); foreach ($stories as $key => $story) { $phids = array(); foreach ($story->getRequiredObjectPHIDs() as $phid) { $phids[$phid] = true; } if ($story->getPrimaryObjectPHID()) { $phids[$story->getPrimaryObjectPHID()] = true; } $key_phids[$key] = $phids; $object_phids += $phids; } $object_query = id(new PhabricatorObjectQuery())->setViewer($viewer)->withPHIDs(array_keys($object_phids)); $objects = $object_query->execute(); foreach ($key_phids as $key => $phids) { if (!$phids) { continue; } $story_objects = array_select_keys($objects, array_keys($phids)); if (count($story_objects) != count($phids)) { // An object this story requires either does not exist or is not visible // to the user. Decline to render the story. unset($stories[$key]); unset($key_phids[$key]); continue; } $stories[$key]->setObjects($story_objects); } // If stories are about PhabricatorProjectInterface objects, load the // projects the objects are a part of so we can render project tags // on the stories. $project_phids = array(); foreach ($objects as $object) { if ($object instanceof PhabricatorProjectInterface) { $project_phids[$object->getPHID()] = array(); } } if ($project_phids) { $edge_query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array_keys($project_phids))->withEdgeTypes(array(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)); $edge_query->execute(); foreach ($project_phids as $phid => $ignored) { $project_phids[$phid] = $edge_query->getDestinationPHIDs(array($phid)); } } $handle_phids = array(); foreach ($stories as $key => $story) { foreach ($story->getRequiredHandlePHIDs() as $phid) { $key_phids[$key][$phid] = true; } if ($story->getAuthorPHID()) { $key_phids[$key][$story->getAuthorPHID()] = true; } $object_phid = $story->getPrimaryObjectPHID(); $object_project_phids = idx($project_phids, $object_phid, array()); $story->setProjectPHIDs($object_project_phids); foreach ($object_project_phids as $dst) { $key_phids[$key][$dst] = true; } $handle_phids += $key_phids[$key]; } // NOTE: This setParentQuery() is a little sketchy. Ideally, this whole // method should be inside FeedQuery and it should be the parent query of // both subqueries. We're just trying to share the workspace cache. $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->setParentQuery($object_query)->withPHIDs(array_keys($handle_phids))->execute(); foreach ($key_phids as $key => $phids) { if (!$phids) { continue; } $story_handles = array_select_keys($handles, array_keys($phids)); $stories[$key]->setHandles($story_handles); } // Load and process story markup blocks. $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($stories as $story) { foreach ($story->getFieldStoryMarkupFields() as $field) { $engine->addObject($story, $field); } } $engine->process(); foreach ($stories as $story) { foreach ($story->getFieldStoryMarkupFields() as $field) { $story->setMarkupFieldOutput($field, $engine->getOutput($story, $field)); } } return $stories; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->id))->needContent(true)->executeOne(); if (!$document) { return new Aphront404Response(); } $current = $document->getContent(); $l = $request->getInt('l'); $r = $request->getInt('r'); $ref = $request->getStr('ref'); if ($ref) { list($l, $r) = explode(',', $ref); } $content = id(new PhrictionContent())->loadAllWhere('documentID = %d AND version IN (%Ld)', $document->getID(), array($l, $r)); $content = mpull($content, null, 'getVersion'); $content_l = idx($content, $l, null); $content_r = idx($content, $r, null); if (!$content_l || !$content_r) { return new Aphront404Response(); } $text_l = $content_l->getContent(); $text_r = $content_r->getContent(); $text_l = phutil_utf8_hard_wrap($text_l, 80); $text_l = implode("\n", $text_l); $text_r = phutil_utf8_hard_wrap($text_r, 80); $text_r = implode("\n", $text_r); $engine = new PhabricatorDifferenceEngine(); $changeset = $engine->generateChangesetFromFileContent($text_l, $text_r); $changeset->setOldProperties(array('Title' => $content_l->getTitle())); $changeset->setNewProperties(array('Title' => $content_r->getTitle())); $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL; $parser = new DifferentialChangesetParser(); $parser->setChangeset($changeset); $parser->setRenderingReference("{$l},{$r}"); $parser->setWhitespaceMode($whitespace_mode); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->process(); $parser->setMarkupEngine($engine); $spec = $request->getStr('range'); list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec); $output = $parser->render($range_s, $range_e, $mask); if ($request->isAjax()) { return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output); } require_celerity_resource('differential-changeset-view-css'); require_celerity_resource('syntax-highlighting-css'); require_celerity_resource('phriction-document-css'); Javelin::initBehavior('differential-show-more', array('uri' => '/phriction/diff/' . $document->getID() . '/', 'whitespace' => $whitespace_mode)); $slug = $document->getSlug(); $revert_l = $this->renderRevertButton($content_l, $current); $revert_r = $this->renderRevertButton($content_r, $current); $crumbs = $this->buildApplicationCrumbs(); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } $crumbs->addTextCrumb(pht('History'), PhrictionDocument::getSlugURI($slug, 'history')); $title = pht('Version %s vs %s', $l, $r); $header = id(new PHUIHeaderView())->setHeader($title); $crumbs->addTextCrumb($title, $request->getRequestURI()); $comparison_table = $this->renderComparisonTable(array($content_r, $content_l)); $navigation_table = null; if ($l + 1 == $r) { $nav_l = $l > 1; $nav_r = $r != $current->getVersion(); $uri = $request->getRequestURI(); if ($nav_l) { $link_l = phutil_tag('a', array('href' => $uri->alter('l', $l - 1)->alter('r', $r - 1), 'class' => 'button'), pht("« Previous Change")); } else { $link_l = phutil_tag('a', array('href' => '#', 'class' => 'button grey disabled'), pht('Original Change')); } $link_r = null; if ($nav_r) { $link_r = phutil_tag('a', array('href' => $uri->alter('l', $l + 1)->alter('r', $r + 1), 'class' => 'button'), pht("Next Change »")); } else { $link_r = phutil_tag('a', array('href' => '#', 'class' => 'button grey disabled'), pht('Most Recent Change')); } $navigation_table = phutil_tag('table', array('class' => 'phriction-history-nav-table'), phutil_tag('tr', array(), array(phutil_tag('td', array('class' => 'nav-prev'), $link_l), phutil_tag('td', array('class' => 'nav-next'), $link_r)))); } $output = hsprintf('<div class="phriction-document-history-diff">' . '%s%s' . '<table class="phriction-revert-table">' . '<tr><td>%s</td><td>%s</td>' . '</table>' . '%s' . '</div>', $comparison_table->render(), $navigation_table, $revert_l, $revert_r, $output); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($output); return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => pht('Document History'))); }
public function processRequest() { $request = $this->getRequest(); $author_phid = $request->getUser()->getPHID(); $rendering_reference = $request->getStr('ref'); $parts = explode('/', $rendering_reference); if (count($parts) == 2) { list($id, $vs) = $parts; } else { $id = $parts[0]; $vs = 0; } $id = (int) $id; $vs = (int) $vs; $load_ids = array($id); if ($vs && $vs != -1) { $load_ids[] = $vs; } $changesets = id(new DifferentialChangesetQuery())->setViewer($request->getUser())->withIDs($load_ids)->needHunks(true)->execute(); $changesets = mpull($changesets, null, 'getID'); $changeset = idx($changesets, $id); if (!$changeset) { return new Aphront404Response(); } $vs_changeset = null; if ($vs && $vs != -1) { $vs_changeset = idx($changesets, $vs); if (!$vs_changeset) { return new Aphront404Response(); } } $view = $request->getStr('view'); if ($view) { $phid = idx($changeset->getMetadata(), "{$view}:binary-phid"); if ($phid) { return id(new AphrontRedirectResponse())->setURI("/file/info/{$phid}/"); } switch ($view) { case 'new': return $this->buildRawFileResponse($changeset, $is_new = true); case 'old': if ($vs_changeset) { return $this->buildRawFileResponse($vs_changeset, $is_new = true); } return $this->buildRawFileResponse($changeset, $is_new = false); default: return new Aphront400Response(); } } if (!$vs) { $right = $changeset; $left = null; $right_source = $right->getID(); $right_new = true; $left_source = $right->getID(); $left_new = false; $render_cache_key = $right->getID(); } else { if ($vs == -1) { $right = null; $left = $changeset; $right_source = $left->getID(); $right_new = false; $left_source = $left->getID(); $left_new = true; $render_cache_key = null; } else { $right = $changeset; $left = $vs_changeset; $right_source = $right->getID(); $right_new = true; $left_source = $left->getID(); $left_new = true; $render_cache_key = null; } } if ($left) { $left_data = $left->makeNewFile(); if ($right) { $right_data = $right->makeNewFile(); } else { $right_data = $left->makeOldFile(); } $engine = new PhabricatorDifferenceEngine(); $synthetic = $engine->generateChangesetFromFileContent($left_data, $right_data); $choice = clone nonempty($left, $right); $choice->attachHunks($synthetic->getHunks()); $changeset = $choice; } $coverage = null; if ($right && $right->getDiffID()) { $unit = id(new DifferentialDiffProperty())->loadOneWhere('diffID = %d AND name = %s', $right->getDiffID(), 'arc:unit'); if ($unit) { $coverage = array(); foreach ($unit->getData() as $result) { $result_coverage = idx($result, 'coverage'); if (!$result_coverage) { continue; } $file_coverage = idx($result_coverage, $right->getFileName()); if (!$file_coverage) { continue; } $coverage[] = $file_coverage; } $coverage = ArcanistUnitTestResult::mergeCoverage($coverage); } } $spec = $request->getStr('range'); list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec); $parser = new DifferentialChangesetParser(); $parser->setCoverage($coverage); $parser->setChangeset($changeset); $parser->setRenderingReference($rendering_reference); $parser->setRenderCacheKey($render_cache_key); $parser->setRightSideCommentMapping($right_source, $right_new); $parser->setLeftSideCommentMapping($left_source, $left_new); $parser->setWhitespaceMode($request->getStr('whitespace')); $parser->setCharacterEncoding($request->getStr('encoding')); $parser->setHighlightAs($request->getStr('highlight')); if ($request->getStr('renderer') == '1up') { $parser->setRenderer(new DifferentialChangesetOneUpRenderer()); } if ($left && $right) { $parser->setOriginals($left, $right); } // Load both left-side and right-side inline comments. $inlines = $this->loadInlineComments(array($left_source, $right_source), $author_phid); if ($left_new) { $inlines = array_merge($inlines, $this->buildLintInlineComments($left)); } if ($right_new) { $inlines = array_merge($inlines, $this->buildLintInlineComments($right)); } $phids = array(); foreach ($inlines as $inline) { $parser->parseInlineComment($inline); if ($inline->getAuthorPHID()) { $phids[$inline->getAuthorPHID()] = true; } } $phids = array_keys($phids); $handles = $this->loadViewerHandles($phids); $parser->setHandles($handles); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($request->getUser()); foreach ($inlines as $inline) { $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); $parser->setMarkupEngine($engine); if ($request->isAjax()) { // TODO: This is sort of lazy, the effect is just to not render "Edit" // and "Reply" links on the "standalone view". $parser->setUser($request->getUser()); } $output = $parser->render($range_s, $range_e, $mask); $mcov = $parser->renderModifiedCoverage(); if ($request->isAjax()) { $coverage = array('differential-mcoverage-' . md5($changeset->getFilename()) => $mcov); return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output)->setCoverage($coverage); } Javelin::initBehavior('differential-show-more', array('uri' => '/differential/changeset/', 'whitespace' => $request->getStr('whitespace'))); Javelin::initBehavior('differential-comment-jump', array()); // TODO: [HTML] Clean up DifferentialChangesetParser output, but it's // undergoing like six kinds of refactoring anyway. $output = phutil_safe_html($output); $detail = new DifferentialChangesetDetailView(); $detail->setChangeset($changeset); $detail->appendChild($output); $detail->setVsChangesetID($left_source); $panel = new DifferentialPrimaryPaneView(); $panel->appendChild(phutil_tag('div', array('class' => 'differential-review-stage', 'id' => 'differential-review-stage'), $detail->render())); $crumbs = $this->buildApplicationCrumbs(); $revision_id = $changeset->getDiff()->getRevisionID(); if ($revision_id) { $crumbs->addTextCrumb('D' . $revision_id, '/D' . $revision_id); } $diff_id = $changeset->getDiff()->getID(); if ($diff_id) { $crumbs->addTextCrumb(pht('Diff %d', $diff_id), $this->getApplicationURI('diff/' . $diff_id)); } $crumbs->addTextCrumb($changeset->getDisplayFilename()); $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Standalone View'))->appendChild($panel); return $this->buildApplicationPage(array($crumbs, $box), array('title' => pht('Changeset View'), 'device' => false)); }