Summary: Replace giant table with PHUIStatusListView. Also remove "MetaMTA Transcripts" (which doesn't work any more) and "Herald Transcripts" (which no one uses).
Test Plan:
{F51437}
{F51438}
Reviewers: chad, btrahan
Reviewed By: chad
CC: aran
Differential Revision: https://secure.phabricator.com/D6562
		
	
		
			
				
	
	
		
			989 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			989 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
final class DiffusionCommitController extends DiffusionController {
 | 
						|
 | 
						|
  const CHANGES_LIMIT = 100;
 | 
						|
 | 
						|
  private $auditAuthorityPHIDs;
 | 
						|
  private $highlightedAudits;
 | 
						|
 | 
						|
  public function willProcessRequest(array $data) {
 | 
						|
    // This controller doesn't use blob/path stuff, just pass the dictionary
 | 
						|
    // in directly instead of using the AphrontRequest parsing mechanism.
 | 
						|
    $data['user'] = $this->getRequest()->getUser();
 | 
						|
    $drequest = DiffusionRequest::newFromDictionary($data);
 | 
						|
    $this->diffusionRequest = $drequest;
 | 
						|
  }
 | 
						|
 | 
						|
  public function processRequest() {
 | 
						|
    $drequest = $this->getDiffusionRequest();
 | 
						|
    $request = $this->getRequest();
 | 
						|
    $user = $request->getUser();
 | 
						|
 | 
						|
    if ($request->getStr('diff')) {
 | 
						|
      return $this->buildRawDiffResponse($drequest);
 | 
						|
    }
 | 
						|
 | 
						|
    $callsign = $drequest->getRepository()->getCallsign();
 | 
						|
 | 
						|
    $content = array();
 | 
						|
    $repository = $drequest->getRepository();
 | 
						|
    $commit = $drequest->loadCommit();
 | 
						|
 | 
						|
    if (!$commit) {
 | 
						|
      $exists = $this->callConduitWithDiffusionRequest(
 | 
						|
        'diffusion.existsquery',
 | 
						|
        array('commit' => $drequest->getCommit()));
 | 
						|
      if (!$exists) {
 | 
						|
        return new Aphront404Response();
 | 
						|
      }
 | 
						|
      return $this->buildStandardPageResponse(
 | 
						|
        id(new AphrontErrorView())
 | 
						|
        ->setTitle(pht('Error displaying commit.'))
 | 
						|
        ->appendChild(pht('Failed to load the commit because the commit has '.
 | 
						|
                      'not been parsed yet.')),
 | 
						|
          array('title' => pht('Commit Still Parsing')));
 | 
						|
    }
 | 
						|
 | 
						|
    $commit_data = $drequest->loadCommitData();
 | 
						|
    $commit->attachCommitData($commit_data);
 | 
						|
 | 
						|
    $top_anchor = id(new PhabricatorAnchorView())
 | 
						|
      ->setAnchorName('top')
 | 
						|
      ->setNavigationMarker(true);
 | 
						|
 | 
						|
    $audit_requests = id(new PhabricatorAuditQuery())
 | 
						|
      ->withCommitPHIDs(array($commit->getPHID()))
 | 
						|
      ->execute();
 | 
						|
    $this->auditAuthorityPHIDs =
 | 
						|
      PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
 | 
						|
 | 
						|
 | 
						|
    $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
 | 
						|
    $changesets = null;
 | 
						|
    if ($is_foreign) {
 | 
						|
      $subpath = $commit_data->getCommitDetail('svn-subpath');
 | 
						|
 | 
						|
      $error_panel = new AphrontErrorView();
 | 
						|
      $error_panel->setTitle(pht('Commit Not Tracked'));
 | 
						|
      $error_panel->setSeverity(AphrontErrorView::SEVERITY_WARNING);
 | 
						|
      $error_panel->appendChild(
 | 
						|
        pht("This Diffusion repository is configured to track only one ".
 | 
						|
        "subdirectory of the entire Subversion repository, and this commit ".
 | 
						|
        "didn't affect the tracked subdirectory ('%s'), so no ".
 | 
						|
        "information is available.", $subpath));
 | 
						|
      $content[] = $error_panel;
 | 
						|
      $content[] = $top_anchor;
 | 
						|
    } else {
 | 
						|
      $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
 | 
						|
      $engine->setConfig('viewer', $user);
 | 
						|
 | 
						|
      require_celerity_resource('diffusion-commit-view-css');
 | 
						|
      require_celerity_resource('phabricator-remarkup-css');
 | 
						|
 | 
						|
      $parents = $this->callConduitWithDiffusionRequest(
 | 
						|
        'diffusion.commitparentsquery',
 | 
						|
        array('commit' => $drequest->getCommit()));
 | 
						|
 | 
						|
      $headsup_view = id(new PhabricatorHeaderView())
 | 
						|
        ->setHeader(nonempty($commit->getSummary(), pht('Commit Detail')));
 | 
						|
 | 
						|
      $headsup_actions = $this->renderHeadsupActionList($commit, $repository);
 | 
						|
 | 
						|
      $commit_properties = $this->loadCommitProperties(
 | 
						|
        $commit,
 | 
						|
        $commit_data,
 | 
						|
        $parents,
 | 
						|
        $audit_requests);
 | 
						|
      $property_list = id(new PhabricatorPropertyListView())
 | 
						|
        ->setHasKeyboardShortcuts(true)
 | 
						|
        ->setUser($user)
 | 
						|
        ->setObject($commit);
 | 
						|
      foreach ($commit_properties as $key => $value) {
 | 
						|
        $property_list->addProperty($key, $value);
 | 
						|
      }
 | 
						|
 | 
						|
      $message = $commit_data->getCommitMessage();
 | 
						|
 | 
						|
      $revision = $commit->getCommitIdentifier();
 | 
						|
      $message = $repository->linkBugtraq($message, $revision);
 | 
						|
 | 
						|
      $message = $engine->markupText($message);
 | 
						|
 | 
						|
      $property_list->invokeWillRenderEvent();
 | 
						|
      $property_list->addTextContent(
 | 
						|
        phutil_tag(
 | 
						|
          'div',
 | 
						|
          array(
 | 
						|
            'class' => 'diffusion-commit-message phabricator-remarkup',
 | 
						|
          ),
 | 
						|
          $message));
 | 
						|
      $content[] = $top_anchor;
 | 
						|
      $content[] = $headsup_view;
 | 
						|
      $content[] = $headsup_actions;
 | 
						|
      $content[] = $property_list;
 | 
						|
    }
 | 
						|
 | 
						|
    $content[] = $this->buildComments($commit);
 | 
						|
 | 
						|
    $hard_limit = 1000;
 | 
						|
 | 
						|
    $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
 | 
						|
      $drequest);
 | 
						|
    $change_query->setLimit($hard_limit + 1);
 | 
						|
    $changes = $change_query->loadChanges();
 | 
						|
 | 
						|
    $was_limited = (count($changes) > $hard_limit);
 | 
						|
    if ($was_limited) {
 | 
						|
      $changes = array_slice($changes, 0, $hard_limit);
 | 
						|
    }
 | 
						|
 | 
						|
    $content[] = $this->buildMergesTable($commit);
 | 
						|
 | 
						|
    $owners_paths = array();
 | 
						|
    if ($this->highlightedAudits) {
 | 
						|
      $packages = id(new PhabricatorOwnersPackage())->loadAllWhere(
 | 
						|
        'phid IN (%Ls)',
 | 
						|
        mpull($this->highlightedAudits, 'getAuditorPHID'));
 | 
						|
      if ($packages) {
 | 
						|
        $owners_paths = id(new PhabricatorOwnersPath())->loadAllWhere(
 | 
						|
          'repositoryPHID = %s AND packageID IN (%Ld)',
 | 
						|
          $repository->getPHID(),
 | 
						|
          mpull($packages, 'getID'));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $change_table = new DiffusionCommitChangeTableView();
 | 
						|
    $change_table->setDiffusionRequest($drequest);
 | 
						|
    $change_table->setPathChanges($changes);
 | 
						|
    $change_table->setOwnersPaths($owners_paths);
 | 
						|
 | 
						|
    $count = count($changes);
 | 
						|
 | 
						|
    $bad_commit = null;
 | 
						|
    if ($count == 0) {
 | 
						|
      $bad_commit = queryfx_one(
 | 
						|
        id(new PhabricatorRepository())->establishConnection('r'),
 | 
						|
        'SELECT * FROM %T WHERE fullCommitName = %s',
 | 
						|
        PhabricatorRepository::TABLE_BADCOMMIT,
 | 
						|
        'r'.$callsign.$commit->getCommitIdentifier());
 | 
						|
    }
 | 
						|
 | 
						|
    if ($bad_commit) {
 | 
						|
      $error_panel = new AphrontErrorView();
 | 
						|
      $error_panel->setTitle(pht('Bad Commit'));
 | 
						|
      $error_panel->appendChild($bad_commit['description']);
 | 
						|
 | 
						|
      $content[] = $error_panel;
 | 
						|
    } else if ($is_foreign) {
 | 
						|
      // Don't render anything else.
 | 
						|
    } else if (!count($changes)) {
 | 
						|
      $no_changes = new AphrontErrorView();
 | 
						|
      $no_changes->setSeverity(AphrontErrorView::SEVERITY_WARNING);
 | 
						|
      $no_changes->setTitle(pht('Not Yet Parsed'));
 | 
						|
      // TODO: This can also happen with weird SVN changes that don't do
 | 
						|
      // anything (or only alter properties?), although the real no-changes case
 | 
						|
      // is extremely rare and might be impossible to produce organically. We
 | 
						|
      // should probably write some kind of "Nothing Happened!" change into the
 | 
						|
      // DB once we parse these changes so we can distinguish between
 | 
						|
      // "not parsed yet" and "no changes".
 | 
						|
      $no_changes->appendChild(
 | 
						|
        pht("This commit hasn't been fully parsed yet (or doesn't affect any ".
 | 
						|
        "paths)."));
 | 
						|
      $content[] = $no_changes;
 | 
						|
    } else if ($was_limited) {
 | 
						|
      $huge_commit = new AphrontErrorView();
 | 
						|
      $huge_commit->setSeverity(AphrontErrorView::SEVERITY_WARNING);
 | 
						|
      $huge_commit->setTitle(pht('Enormous Commit'));
 | 
						|
      $huge_commit->appendChild(
 | 
						|
        pht(
 | 
						|
          'This commit is enormous, and affects more than %d files. '.
 | 
						|
          'Changes are not shown.',
 | 
						|
          $hard_limit));
 | 
						|
      $content[] = $huge_commit;
 | 
						|
    } else {
 | 
						|
      $change_panel = new AphrontPanelView();
 | 
						|
      $change_panel->setHeader("Changes (".number_format($count).")");
 | 
						|
      $change_panel->setID('toc');
 | 
						|
      if ($count > self::CHANGES_LIMIT) {
 | 
						|
        $show_all_button = phutil_tag(
 | 
						|
          'a',
 | 
						|
          array(
 | 
						|
            'class'   => 'button green',
 | 
						|
            'href'    => '?show_all=true',
 | 
						|
          ),
 | 
						|
          pht('Show All Changes'));
 | 
						|
        $warning_view = id(new AphrontErrorView())
 | 
						|
          ->setSeverity(AphrontErrorView::SEVERITY_WARNING)
 | 
						|
          ->setTitle('Very Large Commit')
 | 
						|
          ->appendChild(phutil_tag(
 | 
						|
            'p',
 | 
						|
            array(),
 | 
						|
            pht("This commit is very large. Load each file individually.")));
 | 
						|
 | 
						|
        $change_panel->appendChild($warning_view);
 | 
						|
        $change_panel->addButton($show_all_button);
 | 
						|
      }
 | 
						|
 | 
						|
      $change_panel->appendChild($change_table);
 | 
						|
      $change_panel->setNoBackground();
 | 
						|
 | 
						|
      $content[] = $change_panel;
 | 
						|
 | 
						|
      $changesets = DiffusionPathChange::convertToDifferentialChangesets(
 | 
						|
        $changes);
 | 
						|
 | 
						|
      $vcs = $repository->getVersionControlSystem();
 | 
						|
      switch ($vcs) {
 | 
						|
        case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
 | 
						|
          $vcs_supports_directory_changes = true;
 | 
						|
          break;
 | 
						|
        case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
 | 
						|
        case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
 | 
						|
          $vcs_supports_directory_changes = false;
 | 
						|
          break;
 | 
						|
        default:
 | 
						|
          throw new Exception("Unknown VCS.");
 | 
						|
      }
 | 
						|
 | 
						|
      $references = array();
 | 
						|
      foreach ($changesets as $key => $changeset) {
 | 
						|
        $file_type = $changeset->getFileType();
 | 
						|
        if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
 | 
						|
          if (!$vcs_supports_directory_changes) {
 | 
						|
            unset($changesets[$key]);
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        $references[$key] = $drequest->generateURI(
 | 
						|
          array(
 | 
						|
            'action' => 'rendering-ref',
 | 
						|
            'path'   => $changeset->getFilename(),
 | 
						|
          ));
 | 
						|
      }
 | 
						|
 | 
						|
      // TODO: Some parts of the views still rely on properties of the
 | 
						|
      // DifferentialChangeset. Make the objects ephemeral to make sure we don't
 | 
						|
      // accidentally save them, and then set their ID to the appropriate ID for
 | 
						|
      // this application (the path IDs).
 | 
						|
      $path_ids = array_flip(mpull($changes, 'getPath'));
 | 
						|
      foreach ($changesets as $changeset) {
 | 
						|
        $changeset->makeEphemeral();
 | 
						|
        $changeset->setID($path_ids[$changeset->getFilename()]);
 | 
						|
      }
 | 
						|
 | 
						|
      if ($count <= self::CHANGES_LIMIT) {
 | 
						|
        $visible_changesets = $changesets;
 | 
						|
      } else {
 | 
						|
        $visible_changesets = array();
 | 
						|
        $inlines = id(new PhabricatorAuditInlineComment())->loadAllWhere(
 | 
						|
          'commitPHID = %s AND (auditCommentID IS NOT NULL OR authorPHID = %s)',
 | 
						|
          $commit->getPHID(),
 | 
						|
          $user->getPHID());
 | 
						|
        $path_ids = mpull($inlines, null, 'getPathID');
 | 
						|
        foreach ($changesets as $key => $changeset) {
 | 
						|
          if (array_key_exists($changeset->getID(), $path_ids)) {
 | 
						|
            $visible_changesets[$key] = $changeset;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      $change_list_title = DiffusionView::nameCommit(
 | 
						|
        $repository,
 | 
						|
        $commit->getCommitIdentifier());
 | 
						|
      $change_list = new DifferentialChangesetListView();
 | 
						|
      $change_list->setTitle($change_list_title);
 | 
						|
      $change_list->setChangesets($changesets);
 | 
						|
      $change_list->setVisibleChangesets($visible_changesets);
 | 
						|
      $change_list->setRenderingReferences($references);
 | 
						|
      $change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
 | 
						|
      $change_list->setRepository($repository);
 | 
						|
      $change_list->setUser($user);
 | 
						|
      // pick the first branch for "Browse in Diffusion" View Option
 | 
						|
      $branches     = $commit_data->getCommitDetail('seenOnBranches', array());
 | 
						|
      $first_branch = reset($branches);
 | 
						|
      $change_list->setBranch($first_branch);
 | 
						|
 | 
						|
      $change_list->setStandaloneURI(
 | 
						|
        '/diffusion/'.$callsign.'/diff/');
 | 
						|
      $change_list->setRawFileURIs(
 | 
						|
        // TODO: Implement this, somewhat tricky if there's an octopus merge
 | 
						|
        // or whatever?
 | 
						|
        null,
 | 
						|
        '/diffusion/'.$callsign.'/diff/?view=r');
 | 
						|
 | 
						|
      $change_list->setInlineCommentControllerURI(
 | 
						|
        '/diffusion/inline/edit/'.phutil_escape_uri($commit->getPHID()).'/');
 | 
						|
 | 
						|
      $change_references = array();
 | 
						|
      foreach ($changesets as $key => $changeset) {
 | 
						|
        $change_references[$changeset->getID()] = $references[$key];
 | 
						|
      }
 | 
						|
      $change_table->setRenderingReferences($change_references);
 | 
						|
 | 
						|
      $content[] = $change_list->render();
 | 
						|
    }
 | 
						|
 | 
						|
    $content[] = $this->renderAddCommentPanel($commit, $audit_requests);
 | 
						|
 | 
						|
    $commit_id = 'r'.$callsign.$commit->getCommitIdentifier();
 | 
						|
    $short_name = DiffusionView::nameCommit(
 | 
						|
      $repository,
 | 
						|
      $commit->getCommitIdentifier());
 | 
						|
 | 
						|
    $crumbs = $this->buildCrumbs(array(
 | 
						|
      'commit' => true,
 | 
						|
    ));
 | 
						|
 | 
						|
    $prefs = $user->loadPreferences();
 | 
						|
    $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
 | 
						|
    $pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
 | 
						|
    $show_filetree = $prefs->getPreference($pref_filetree);
 | 
						|
    $collapsed = $prefs->getPreference($pref_collapse);
 | 
						|
 | 
						|
    if ($changesets && $show_filetree) {
 | 
						|
      $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())
 | 
						|
        ->setAnchorName('top')
 | 
						|
        ->setTitle($short_name)
 | 
						|
        ->setBaseURI(new PhutilURI('/'.$commit_id))
 | 
						|
        ->build($changesets)
 | 
						|
        ->setCrumbs($crumbs)
 | 
						|
        ->setCollapsed((bool)$collapsed)
 | 
						|
        ->appendChild($content);
 | 
						|
      $content = $nav;
 | 
						|
    } else {
 | 
						|
      $content = array($crumbs, $content);
 | 
						|
    }
 | 
						|
 | 
						|
    return $this->buildApplicationPage(
 | 
						|
      $content,
 | 
						|
      array(
 | 
						|
        'title' => $commit_id,
 | 
						|
        'pageObjects' => array($commit->getPHID()),
 | 
						|
        'dust' => true,
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  private function loadCommitProperties(
 | 
						|
    PhabricatorRepositoryCommit $commit,
 | 
						|
    PhabricatorRepositoryCommitData $data,
 | 
						|
    array $parents,
 | 
						|
    array $audit_requests) {
 | 
						|
 | 
						|
    assert_instances_of($parents, 'PhabricatorRepositoryCommit');
 | 
						|
    $user = $this->getRequest()->getUser();
 | 
						|
    $commit_phid = $commit->getPHID();
 | 
						|
 | 
						|
    $edge_query = id(new PhabricatorEdgeQuery())
 | 
						|
      ->withSourcePHIDs(array($commit_phid))
 | 
						|
      ->withEdgeTypes(array(
 | 
						|
        PhabricatorEdgeConfig::TYPE_COMMIT_HAS_TASK,
 | 
						|
        PhabricatorEdgeConfig::TYPE_COMMIT_HAS_PROJECT,
 | 
						|
        PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV,
 | 
						|
      ));
 | 
						|
 | 
						|
    $edges = $edge_query->execute();
 | 
						|
 | 
						|
    $task_phids = array_keys(
 | 
						|
      $edges[$commit_phid][PhabricatorEdgeConfig::TYPE_COMMIT_HAS_TASK]);
 | 
						|
    $proj_phids = array_keys(
 | 
						|
      $edges[$commit_phid][PhabricatorEdgeConfig::TYPE_COMMIT_HAS_PROJECT]);
 | 
						|
    $revision_phid = key(
 | 
						|
      $edges[$commit_phid][PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV]);
 | 
						|
 | 
						|
    $phids = $edge_query->getDestinationPHIDs(array($commit_phid));
 | 
						|
 | 
						|
    if ($data->getCommitDetail('authorPHID')) {
 | 
						|
      $phids[] = $data->getCommitDetail('authorPHID');
 | 
						|
    }
 | 
						|
    if ($data->getCommitDetail('reviewerPHID')) {
 | 
						|
      $phids[] = $data->getCommitDetail('reviewerPHID');
 | 
						|
    }
 | 
						|
    if ($data->getCommitDetail('committerPHID')) {
 | 
						|
      $phids[] = $data->getCommitDetail('committerPHID');
 | 
						|
    }
 | 
						|
    if ($parents) {
 | 
						|
      foreach ($parents as $parent) {
 | 
						|
        $phids[] = $parent->getPHID();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $handles = array();
 | 
						|
    if ($phids) {
 | 
						|
      $handles = $this->loadViewerHandles($phids);
 | 
						|
    }
 | 
						|
 | 
						|
    $props = array();
 | 
						|
 | 
						|
    if ($commit->getAuditStatus()) {
 | 
						|
      $status = PhabricatorAuditCommitStatusConstants::getStatusName(
 | 
						|
        $commit->getAuditStatus());
 | 
						|
      $tag = id(new PhabricatorTagView())
 | 
						|
        ->setType(PhabricatorTagView::TYPE_STATE)
 | 
						|
        ->setName($status);
 | 
						|
 | 
						|
      switch ($commit->getAuditStatus()) {
 | 
						|
        case PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT:
 | 
						|
          $tag->setBackgroundColor(PhabricatorTagView::COLOR_ORANGE);
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditCommitStatusConstants::CONCERN_RAISED:
 | 
						|
          $tag->setBackgroundColor(PhabricatorTagView::COLOR_RED);
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED:
 | 
						|
          $tag->setBackgroundColor(PhabricatorTagView::COLOR_BLUE);
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditCommitStatusConstants::FULLY_AUDITED:
 | 
						|
          $tag->setBackgroundColor(PhabricatorTagView::COLOR_GREEN);
 | 
						|
          break;
 | 
						|
      }
 | 
						|
 | 
						|
      $props['Status'] = $tag;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($audit_requests) {
 | 
						|
      $props['Auditors'] = $this->renderAuditStatusView($audit_requests);
 | 
						|
    }
 | 
						|
 | 
						|
    $props['Committed'] = phabricator_datetime($commit->getEpoch(), $user);
 | 
						|
 | 
						|
    $author_phid = $data->getCommitDetail('authorPHID');
 | 
						|
    if ($data->getCommitDetail('authorPHID')) {
 | 
						|
      $props['Author'] = $handles[$author_phid]->renderLink();
 | 
						|
    } else {
 | 
						|
      $props['Author'] = $data->getAuthorName();
 | 
						|
    }
 | 
						|
 | 
						|
    $reviewer_phid = $data->getCommitDetail('reviewerPHID');
 | 
						|
    if ($reviewer_phid) {
 | 
						|
      $props['Reviewer'] = $handles[$reviewer_phid]->renderLink();
 | 
						|
    }
 | 
						|
 | 
						|
    $committer = $data->getCommitDetail('committer');
 | 
						|
    if ($committer) {
 | 
						|
      $committer_phid = $data->getCommitDetail('committerPHID');
 | 
						|
      if ($data->getCommitDetail('committerPHID')) {
 | 
						|
        $props['Committer'] = $handles[$committer_phid]->renderLink();
 | 
						|
      } else {
 | 
						|
        $props['Committer'] = $committer;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($revision_phid) {
 | 
						|
      $props['Differential Revision'] = $handles[$revision_phid]->renderLink();
 | 
						|
    }
 | 
						|
 | 
						|
    if ($parents) {
 | 
						|
      $parent_links = array();
 | 
						|
      foreach ($parents as $parent) {
 | 
						|
        $parent_links[] = $handles[$parent->getPHID()]->renderLink();
 | 
						|
      }
 | 
						|
      $props['Parents'] = phutil_implode_html(" \xC2\xB7 ", $parent_links);
 | 
						|
    }
 | 
						|
 | 
						|
    $request = $this->getDiffusionRequest();
 | 
						|
 | 
						|
    $props['Branches'] = phutil_tag(
 | 
						|
      'span',
 | 
						|
      array(
 | 
						|
        'id' => 'commit-branches',
 | 
						|
      ),
 | 
						|
      pht('Unknown'));
 | 
						|
    $props['Tags'] = phutil_tag(
 | 
						|
      'span',
 | 
						|
      array(
 | 
						|
        'id' => 'commit-tags',
 | 
						|
      ),
 | 
						|
      pht('Unknown'));
 | 
						|
 | 
						|
    $callsign = $request->getRepository()->getCallsign();
 | 
						|
    $root = '/diffusion/'.$callsign.'/commit/'.$commit->getCommitIdentifier();
 | 
						|
    Javelin::initBehavior(
 | 
						|
      'diffusion-commit-branches',
 | 
						|
      array(
 | 
						|
        $root.'/branches/' => 'commit-branches',
 | 
						|
        $root.'/tags/' => 'commit-tags',
 | 
						|
      ));
 | 
						|
 | 
						|
    $refs = $this->buildRefs($request);
 | 
						|
    if ($refs) {
 | 
						|
      $props['References'] = $refs;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($task_phids) {
 | 
						|
      $task_list = array();
 | 
						|
      foreach ($task_phids as $phid) {
 | 
						|
        $task_list[] = $handles[$phid]->renderLink();
 | 
						|
      }
 | 
						|
      $task_list = phutil_implode_html(phutil_tag('br'), $task_list);
 | 
						|
      $props['Tasks'] = $task_list;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($proj_phids) {
 | 
						|
      $proj_list = array();
 | 
						|
      foreach ($proj_phids as $phid) {
 | 
						|
        $proj_list[] = $handles[$phid]->renderLink();
 | 
						|
      }
 | 
						|
      $proj_list = phutil_implode_html(phutil_tag('br'), $proj_list);
 | 
						|
      $props['Projects'] = $proj_list;
 | 
						|
    }
 | 
						|
 | 
						|
    return $props;
 | 
						|
  }
 | 
						|
 | 
						|
  private function buildComments(PhabricatorRepositoryCommit $commit) {
 | 
						|
    $user = $this->getRequest()->getUser();
 | 
						|
    $comments = id(new PhabricatorAuditComment())->loadAllWhere(
 | 
						|
      'targetPHID = %s ORDER BY dateCreated ASC',
 | 
						|
      $commit->getPHID());
 | 
						|
 | 
						|
    $inlines = id(new PhabricatorAuditInlineComment())->loadAllWhere(
 | 
						|
      'commitPHID = %s AND auditCommentID IS NOT NULL',
 | 
						|
      $commit->getPHID());
 | 
						|
 | 
						|
    $path_ids = mpull($inlines, 'getPathID');
 | 
						|
 | 
						|
    $path_map = array();
 | 
						|
    if ($path_ids) {
 | 
						|
      $path_map = id(new DiffusionPathQuery())
 | 
						|
        ->withPathIDs($path_ids)
 | 
						|
        ->execute();
 | 
						|
      $path_map = ipull($path_map, 'path', 'id');
 | 
						|
    }
 | 
						|
 | 
						|
    $engine = new PhabricatorMarkupEngine();
 | 
						|
    $engine->setViewer($user);
 | 
						|
 | 
						|
    foreach ($comments as $comment) {
 | 
						|
      $engine->addObject(
 | 
						|
        $comment,
 | 
						|
        PhabricatorAuditComment::MARKUP_FIELD_BODY);
 | 
						|
    }
 | 
						|
 | 
						|
    foreach ($inlines as $inline) {
 | 
						|
      $engine->addObject(
 | 
						|
        $inline,
 | 
						|
        PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
 | 
						|
    }
 | 
						|
 | 
						|
    $engine->process();
 | 
						|
 | 
						|
    $view = new DiffusionCommentListView();
 | 
						|
    $view->setMarkupEngine($engine);
 | 
						|
    $view->setUser($user);
 | 
						|
    $view->setComments($comments);
 | 
						|
    $view->setInlineComments($inlines);
 | 
						|
    $view->setPathMap($path_map);
 | 
						|
 | 
						|
    $phids = $view->getRequiredHandlePHIDs();
 | 
						|
    $handles = $this->loadViewerHandles($phids);
 | 
						|
    $view->setHandles($handles);
 | 
						|
 | 
						|
    return $view;
 | 
						|
  }
 | 
						|
 | 
						|
  private function renderAddCommentPanel(
 | 
						|
    PhabricatorRepositoryCommit $commit,
 | 
						|
    array $audit_requests) {
 | 
						|
    assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
 | 
						|
    $user = $this->getRequest()->getUser();
 | 
						|
 | 
						|
    $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
 | 
						|
 | 
						|
    $pane_id = celerity_generate_unique_node_id();
 | 
						|
    Javelin::initBehavior(
 | 
						|
      'differential-keyboard-navigation',
 | 
						|
      array(
 | 
						|
        'haunt' => $pane_id,
 | 
						|
      ));
 | 
						|
 | 
						|
    $draft = id(new PhabricatorDraft())->loadOneWhere(
 | 
						|
      'authorPHID = %s AND draftKey = %s',
 | 
						|
      $user->getPHID(),
 | 
						|
      'diffusion-audit-'.$commit->getID());
 | 
						|
    if ($draft) {
 | 
						|
      $draft = $draft->getDraft();
 | 
						|
    } else {
 | 
						|
      $draft = null;
 | 
						|
    }
 | 
						|
 | 
						|
    $actions = $this->getAuditActions($commit, $audit_requests);
 | 
						|
 | 
						|
    $form = id(new AphrontFormView())
 | 
						|
      ->setUser($user)
 | 
						|
      ->setAction('/audit/addcomment/')
 | 
						|
      ->addHiddenInput('commit', $commit->getPHID())
 | 
						|
      ->appendChild(
 | 
						|
        id(new AphrontFormSelectControl())
 | 
						|
          ->setLabel(pht('Action'))
 | 
						|
          ->setName('action')
 | 
						|
          ->setID('audit-action')
 | 
						|
          ->setOptions($actions))
 | 
						|
      ->appendChild(
 | 
						|
        id(new AphrontFormTokenizerControl())
 | 
						|
          ->setLabel(pht('Add Auditors'))
 | 
						|
          ->setName('auditors')
 | 
						|
          ->setControlID('add-auditors')
 | 
						|
          ->setControlStyle('display: none')
 | 
						|
          ->setID('add-auditors-tokenizer')
 | 
						|
          ->setDisableBehavior(true))
 | 
						|
      ->appendChild(
 | 
						|
        id(new AphrontFormTokenizerControl())
 | 
						|
          ->setLabel(pht('Add CCs'))
 | 
						|
          ->setName('ccs')
 | 
						|
          ->setControlID('add-ccs')
 | 
						|
          ->setControlStyle('display: none')
 | 
						|
          ->setID('add-ccs-tokenizer')
 | 
						|
          ->setDisableBehavior(true))
 | 
						|
      ->appendChild(
 | 
						|
        id(new PhabricatorRemarkupControl())
 | 
						|
          ->setLabel(pht('Comments'))
 | 
						|
          ->setName('content')
 | 
						|
          ->setValue($draft)
 | 
						|
          ->setID('audit-content')
 | 
						|
          ->setUser($user))
 | 
						|
      ->appendChild(
 | 
						|
        id(new AphrontFormSubmitControl())
 | 
						|
          ->setValue($is_serious ? pht('Submit') : pht('Cook the Books')));
 | 
						|
 | 
						|
    $header = new PhabricatorHeaderView();
 | 
						|
    $header->setHeader(
 | 
						|
      $is_serious ? pht('Audit Commit') : pht('Creative Accounting'));
 | 
						|
 | 
						|
    require_celerity_resource('phabricator-transaction-view-css');
 | 
						|
 | 
						|
    Javelin::initBehavior(
 | 
						|
      'differential-add-reviewers-and-ccs',
 | 
						|
      array(
 | 
						|
        'dynamic' => array(
 | 
						|
          'add-auditors-tokenizer' => array(
 | 
						|
            'actions' => array('add_auditors' => 1),
 | 
						|
            'src' => '/typeahead/common/users/',
 | 
						|
            'row' => 'add-auditors',
 | 
						|
            'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'),
 | 
						|
            'placeholder' => pht('Type a user name...'),
 | 
						|
          ),
 | 
						|
          'add-ccs-tokenizer' => array(
 | 
						|
            'actions' => array('add_ccs' => 1),
 | 
						|
            'src' => '/typeahead/common/mailable/',
 | 
						|
            'row' => 'add-ccs',
 | 
						|
            'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'),
 | 
						|
            'placeholder' => pht('Type a user or mailing list...'),
 | 
						|
          ),
 | 
						|
        ),
 | 
						|
        'select' => 'audit-action',
 | 
						|
      ));
 | 
						|
 | 
						|
    Javelin::initBehavior('differential-feedback-preview', array(
 | 
						|
      'uri'       => '/audit/preview/'.$commit->getID().'/',
 | 
						|
      'preview'   => 'audit-preview',
 | 
						|
      'content'   => 'audit-content',
 | 
						|
      'action'    => 'audit-action',
 | 
						|
      'previewTokenizers' => array(
 | 
						|
        'auditors' => 'add-auditors-tokenizer',
 | 
						|
        'ccs'      => 'add-ccs-tokenizer',
 | 
						|
      ),
 | 
						|
      'inline'     => 'inline-comment-preview',
 | 
						|
      'inlineuri'  => '/diffusion/inline/preview/'.$commit->getPHID().'/',
 | 
						|
    ));
 | 
						|
 | 
						|
    $preview_panel = hsprintf(
 | 
						|
      '<div class="aphront-panel-preview aphront-panel-flush">
 | 
						|
        <div id="audit-preview">
 | 
						|
          <div class="aphront-panel-preview-loading-text">
 | 
						|
            Loading preview...
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
        <div id="inline-comment-preview">
 | 
						|
        </div>
 | 
						|
      </div>');
 | 
						|
 | 
						|
    // TODO: This is pretty awkward, unify the CSS between Diffusion and
 | 
						|
    // Differential better.
 | 
						|
    require_celerity_resource('differential-core-view-css');
 | 
						|
 | 
						|
    return phutil_tag(
 | 
						|
      'div',
 | 
						|
      array(
 | 
						|
        'id' => $pane_id,
 | 
						|
      ),
 | 
						|
      hsprintf(
 | 
						|
        '<div class="differential-add-comment-panel">%s%s%s%s</div>',
 | 
						|
        id(new PhabricatorAnchorView())
 | 
						|
          ->setAnchorName('comment')
 | 
						|
          ->setNavigationMarker(true)
 | 
						|
          ->render(),
 | 
						|
        $header,
 | 
						|
        $form,
 | 
						|
        $preview_panel));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return a map of available audit actions for rendering into a <select />.
 | 
						|
   * This shows the user valid actions, and does not show nonsense/invalid
 | 
						|
   * actions (like closing an already-closed commit, or resigning from a commit
 | 
						|
   * you have no association with).
 | 
						|
   */
 | 
						|
  private function getAuditActions(
 | 
						|
    PhabricatorRepositoryCommit $commit,
 | 
						|
    array $audit_requests) {
 | 
						|
    assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
 | 
						|
    $user = $this->getRequest()->getUser();
 | 
						|
 | 
						|
    $user_is_author = ($commit->getAuthorPHID() == $user->getPHID());
 | 
						|
 | 
						|
    $user_request = null;
 | 
						|
    foreach ($audit_requests as $audit_request) {
 | 
						|
      if ($audit_request->getAuditorPHID() == $user->getPHID()) {
 | 
						|
        $user_request = $audit_request;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $actions = array();
 | 
						|
    $actions[PhabricatorAuditActionConstants::COMMENT] = true;
 | 
						|
    $actions[PhabricatorAuditActionConstants::ADD_CCS] = true;
 | 
						|
    $actions[PhabricatorAuditActionConstants::ADD_AUDITORS] = true;
 | 
						|
 | 
						|
    // We allow you to accept your own commits. A use case here is that you
 | 
						|
    // notice an issue with your own commit and "Raise Concern" as an indicator
 | 
						|
    // to other auditors that you're on top of the issue, then later resolve it
 | 
						|
    // and "Accept". You can not accept on behalf of projects or packages,
 | 
						|
    // however.
 | 
						|
    $actions[PhabricatorAuditActionConstants::ACCEPT]  = true;
 | 
						|
    $actions[PhabricatorAuditActionConstants::CONCERN] = true;
 | 
						|
 | 
						|
 | 
						|
    // To resign, a user must have authority on some request and not be the
 | 
						|
    // commit's author.
 | 
						|
    if (!$user_is_author) {
 | 
						|
      $may_resign = false;
 | 
						|
 | 
						|
      $authority_map = array_fill_keys($this->auditAuthorityPHIDs, true);
 | 
						|
      foreach ($audit_requests as $request) {
 | 
						|
        if (empty($authority_map[$request->getAuditorPHID()])) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
        $may_resign = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      // If the user has already resigned, don't show "Resign...".
 | 
						|
      $status_resigned = PhabricatorAuditStatusConstants::RESIGNED;
 | 
						|
      if ($user_request) {
 | 
						|
        if ($user_request->getAuditStatus() == $status_resigned) {
 | 
						|
          $may_resign = false;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if ($may_resign) {
 | 
						|
        $actions[PhabricatorAuditActionConstants::RESIGN] = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    $status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
 | 
						|
    $concern_raised = ($commit->getAuditStatus() == $status_concern);
 | 
						|
    $can_close_option = PhabricatorEnv::getEnvConfig(
 | 
						|
      'audit.can-author-close-audit');
 | 
						|
    if ($can_close_option && $user_is_author && $concern_raised) {
 | 
						|
      $actions[PhabricatorAuditActionConstants::CLOSE] = true;
 | 
						|
    }
 | 
						|
 | 
						|
    foreach ($actions as $constant => $ignored) {
 | 
						|
      $actions[$constant] =
 | 
						|
        PhabricatorAuditActionConstants::getActionName($constant);
 | 
						|
    }
 | 
						|
 | 
						|
    return $actions;
 | 
						|
  }
 | 
						|
 | 
						|
  private function buildMergesTable(PhabricatorRepositoryCommit $commit) {
 | 
						|
    $drequest = $this->getDiffusionRequest();
 | 
						|
    $limit = 50;
 | 
						|
 | 
						|
    $merges = array();
 | 
						|
    try {
 | 
						|
      $merges = $this->callConduitWithDiffusionRequest(
 | 
						|
        'diffusion.mergedcommitsquery',
 | 
						|
        array(
 | 
						|
          'commit' => $drequest->getCommit(),
 | 
						|
          'limit' => $limit + 1));
 | 
						|
    } catch (ConduitException $ex) {
 | 
						|
      if ($ex->getMessage() != 'ERR-UNSUPPORTED-VCS') {
 | 
						|
        throw $ex;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!$merges) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    $caption = null;
 | 
						|
    if (count($merges) > $limit) {
 | 
						|
      $merges = array_slice($merges, 0, $limit);
 | 
						|
      $caption =
 | 
						|
        "This commit merges more than {$limit} changes. Only the first ".
 | 
						|
        "{$limit} are shown.";
 | 
						|
    }
 | 
						|
 | 
						|
    $history_table = new DiffusionHistoryTableView();
 | 
						|
    $history_table->setUser($this->getRequest()->getUser());
 | 
						|
    $history_table->setDiffusionRequest($drequest);
 | 
						|
    $history_table->setHistory($merges);
 | 
						|
    $history_table->loadRevisions();
 | 
						|
 | 
						|
    $phids = $history_table->getRequiredHandlePHIDs();
 | 
						|
    $handles = $this->loadViewerHandles($phids);
 | 
						|
    $history_table->setHandles($handles);
 | 
						|
 | 
						|
    $panel = new AphrontPanelView();
 | 
						|
    $panel->setHeader(pht('Merged Changes'));
 | 
						|
    $panel->setCaption($caption);
 | 
						|
    $panel->appendChild($history_table);
 | 
						|
    $panel->setNoBackground();
 | 
						|
 | 
						|
    return $panel;
 | 
						|
  }
 | 
						|
 | 
						|
  private function renderHeadsupActionList(
 | 
						|
    PhabricatorRepositoryCommit $commit,
 | 
						|
    PhabricatorRepository $repository) {
 | 
						|
 | 
						|
    $request = $this->getRequest();
 | 
						|
    $user = $request->getUser();
 | 
						|
 | 
						|
    $actions = id(new PhabricatorActionListView())
 | 
						|
      ->setUser($user)
 | 
						|
      ->setObject($commit)
 | 
						|
      ->setObjectURI($request->getRequestURI());
 | 
						|
 | 
						|
    // TODO -- integrate permissions into whether or not this action is shown
 | 
						|
    $uri = '/diffusion/'.$repository->getCallSign().'/commit/'.
 | 
						|
           $commit->getCommitIdentifier().'/edit/';
 | 
						|
 | 
						|
    $action = id(new PhabricatorActionView())
 | 
						|
      ->setName(pht('Edit Commit'))
 | 
						|
      ->setHref($uri)
 | 
						|
      ->setIcon('edit');
 | 
						|
    $actions->addAction($action);
 | 
						|
 | 
						|
    require_celerity_resource('phabricator-object-selector-css');
 | 
						|
    require_celerity_resource('javelin-behavior-phabricator-object-selector');
 | 
						|
 | 
						|
    $maniphest = 'PhabricatorApplicationManiphest';
 | 
						|
    if (PhabricatorApplication::isClassInstalled($maniphest)) {
 | 
						|
      $action = id(new PhabricatorActionView())
 | 
						|
        ->setName(pht('Edit Maniphest Tasks'))
 | 
						|
        ->setIcon('attach')
 | 
						|
        ->setHref('/search/attach/'.$commit->getPHID().'/TASK/edge/')
 | 
						|
        ->setWorkflow(true);
 | 
						|
      $actions->addAction($action);
 | 
						|
    }
 | 
						|
 | 
						|
    $action = id(new PhabricatorActionView())
 | 
						|
      ->setName(pht('Download Raw Diff'))
 | 
						|
      ->setHref($request->getRequestURI()->alter('diff', true))
 | 
						|
      ->setIcon('download');
 | 
						|
    $actions->addAction($action);
 | 
						|
 | 
						|
    return $actions;
 | 
						|
  }
 | 
						|
 | 
						|
  private function buildRefs(DiffusionRequest $request) {
 | 
						|
    // this is git-only, so save a conduit round trip and just get out of
 | 
						|
    // here if the repository isn't git
 | 
						|
    $type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
 | 
						|
    $repository = $request->getRepository();
 | 
						|
    if ($repository->getVersionControlSystem() != $type_git) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    $results = $this->callConduitWithDiffusionRequest(
 | 
						|
      'diffusion.refsquery',
 | 
						|
      array('commit' => $request->getCommit()));
 | 
						|
    $ref_links = array();
 | 
						|
    foreach ($results as $ref_data) {
 | 
						|
      $ref_links[] = phutil_tag('a',
 | 
						|
        array('href' => $ref_data['href']),
 | 
						|
        $ref_data['ref']);
 | 
						|
    }
 | 
						|
    return phutil_implode_html(', ', $ref_links);
 | 
						|
  }
 | 
						|
 | 
						|
  private function buildRawDiffResponse(DiffusionRequest $drequest) {
 | 
						|
    $raw_diff = $this->callConduitWithDiffusionRequest(
 | 
						|
      'diffusion.rawdiffquery',
 | 
						|
      array(
 | 
						|
        'commit' => $drequest->getCommit(),
 | 
						|
        'path' => $drequest->getPath()));
 | 
						|
 | 
						|
    $file = PhabricatorFile::buildFromFileDataOrHash(
 | 
						|
      $raw_diff,
 | 
						|
      array(
 | 
						|
        'name' => $drequest->getCommit().'.diff',
 | 
						|
      ));
 | 
						|
 | 
						|
    return id(new AphrontRedirectResponse())->setURI($file->getBestURI());
 | 
						|
  }
 | 
						|
 | 
						|
  private function renderAuditStatusView(array $audit_requests) {
 | 
						|
    assert_instances_of($audit_requests, 'PhabricatorRepositoryAuditRequest');
 | 
						|
 | 
						|
    $phids = mpull($audit_requests, 'getAuditorPHID');
 | 
						|
    $this->loadHandles($phids);
 | 
						|
 | 
						|
    $authority_map = array_fill_keys($this->auditAuthorityPHIDs, true);
 | 
						|
 | 
						|
    $view = new PHUIStatusListView();
 | 
						|
    foreach ($audit_requests as $request) {
 | 
						|
      $item = new PHUIStatusItemView();
 | 
						|
 | 
						|
      switch ($request->getAuditStatus()) {
 | 
						|
        case PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED:
 | 
						|
          $item->setIcon('open-blue', pht('Commented'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::AUDIT_REQUIRED:
 | 
						|
          $item->setIcon('warning-blue', pht('Audit Required'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::CONCERNED:
 | 
						|
          $item->setIcon('reject-red', pht('Concern Raised'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::ACCEPTED:
 | 
						|
          $item->setIcon('accept-green', pht('Accepted'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::AUDIT_REQUESTED:
 | 
						|
          $item->setIcon('warning-dark', pht('Audit Requested'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::RESIGNED:
 | 
						|
          $item->setIcon('open-dark', pht('Accepted'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::CLOSED:
 | 
						|
          $item->setIcon('accept-blue', pht('Accepted'));
 | 
						|
          break;
 | 
						|
        case PhabricatorAuditStatusConstants::CC:
 | 
						|
          $item->setIcon('info-dark', pht('Subscribed'));
 | 
						|
          break;
 | 
						|
      }
 | 
						|
 | 
						|
      $note = array();
 | 
						|
      foreach ($request->getAuditReasons() as $reason) {
 | 
						|
        $note[] = phutil_tag('div', array(), $reason);
 | 
						|
      }
 | 
						|
      $item->setNote($note);
 | 
						|
 | 
						|
      $auditor_phid = $request->getAuditorPHID();
 | 
						|
      $target = $this->getHandle($auditor_phid)->renderLink();
 | 
						|
      $item->setTarget($target);
 | 
						|
 | 
						|
      if (isset($authority_map[$auditor_phid])) {
 | 
						|
        $item->setHighlighted(true);
 | 
						|
      }
 | 
						|
 | 
						|
      $view->addItem($item);
 | 
						|
    }
 | 
						|
 | 
						|
    return $view;
 | 
						|
  }
 | 
						|
 | 
						|
}
 |