private function buildTagListTable(DiffusionRequest $drequest)
 {
     $tag_limit = 15;
     $query = DiffusionTagListQuery::newFromDiffusionRequest($drequest);
     $query->setLimit($tag_limit + 1);
     $tags = $query->loadTags();
     if (!$tags) {
         return null;
     }
     $more_tags = count($tags) > $tag_limit;
     $tags = array_slice($tags, 0, $tag_limit);
     $commits = id(new PhabricatorAuditCommitQuery())->withIdentifiers($drequest->getRepository()->getID(), mpull($tags, 'getCommitIdentifier'))->needCommitData(true)->execute();
     $view = new DiffusionTagListView();
     $view->setDiffusionRequest($drequest);
     $view->setTags($tags);
     $view->setUser($this->getRequest()->getUser());
     $view->setCommits($commits);
     $phids = $view->getRequiredHandlePHIDs();
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $view->setHandles($handles);
     $panel = new AphrontPanelView();
     $panel->setHeader('Tags');
     if ($more_tags) {
         $panel->setCaption('Showing the ' . $tag_limit . ' most recent tags.');
     }
     $panel->addButton(phutil_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'tags')), 'class' => 'grey button'), "Show All Tags »"));
     $panel->appendChild($view);
     return $panel;
 }
 public function renderBurn()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $handle = null;
     $project_phid = $request->getStr('project');
     if ($project_phid) {
         $phids = array($project_phid);
         $handles = $this->loadViewerHandles($phids);
         $handle = $handles[$project_phid];
     }
     $table = new ManiphestTransaction();
     $conn = $table->establishConnection('r');
     $joins = '';
     if ($project_phid) {
         $joins = qsprintf($conn, 'JOIN %T t ON x.taskID = t.id
       JOIN %T p ON p.taskPHID = t.phid AND p.projectPHID = %s', id(new ManiphestTask())->getTableName(), id(new ManiphestTaskProject())->getTableName(), $project_phid);
     }
     $data = queryfx_all($conn, 'SELECT x.oldValue, x.newValue, x.dateCreated FROM %T x %Q
     WHERE transactionType = %s
     ORDER BY x.dateCreated ASC', $table->getTableName(), $joins, ManiphestTransactionType::TYPE_STATUS);
     $stats = array();
     $day_buckets = array();
     $open_tasks = array();
     foreach ($data as $key => $row) {
         // NOTE: Hack to avoid json_decode().
         $oldv = trim($row['oldValue'], '"');
         $newv = trim($row['newValue'], '"');
         $old_is_open = $oldv === (string) ManiphestTaskStatus::STATUS_OPEN;
         $new_is_open = $newv === (string) ManiphestTaskStatus::STATUS_OPEN;
         $is_open = $new_is_open && !$old_is_open;
         $is_close = $old_is_open && !$new_is_open;
         $data[$key]['_is_open'] = $is_open;
         $data[$key]['_is_close'] = $is_close;
         if (!$is_open && !$is_close) {
             // This is either some kind of bogus event, or a resolution change
             // (e.g., resolved -> invalid). Just skip it.
             continue;
         }
         $day_bucket = phabricator_format_local_time($row['dateCreated'], $user, 'Yz');
         $day_buckets[$day_bucket] = $row['dateCreated'];
         if (empty($stats[$day_bucket])) {
             $stats[$day_bucket] = array('open' => 0, 'close' => 0);
         }
         $stats[$day_bucket][$is_close ? 'close' : 'open']++;
     }
     $template = array('open' => 0, 'close' => 0);
     $rows = array();
     $rowc = array();
     $last_month = null;
     $last_month_epoch = null;
     $last_week = null;
     $last_week_epoch = null;
     $week = null;
     $month = null;
     $last = last_key($stats) - 1;
     $period = $template;
     foreach ($stats as $bucket => $info) {
         $epoch = $day_buckets[$bucket];
         $week_bucket = phabricator_format_local_time($epoch, $user, 'YW');
         if ($week_bucket != $last_week) {
             if ($week) {
                 $rows[] = $this->formatBurnRow('Week of ' . phabricator_date($last_week_epoch, $user), $week);
                 $rowc[] = 'week';
             }
             $week = $template;
             $last_week = $week_bucket;
             $last_week_epoch = $epoch;
         }
         $month_bucket = phabricator_format_local_time($epoch, $user, 'Ym');
         if ($month_bucket != $last_month) {
             if ($month) {
                 $rows[] = $this->formatBurnRow(phabricator_format_local_time($last_month_epoch, $user, 'F, Y'), $month);
                 $rowc[] = 'month';
             }
             $month = $template;
             $last_month = $month_bucket;
             $last_month_epoch = $epoch;
         }
         $rows[] = $this->formatBurnRow(phabricator_date($epoch, $user), $info);
         $rowc[] = null;
         $week['open'] += $info['open'];
         $week['close'] += $info['close'];
         $month['open'] += $info['open'];
         $month['close'] += $info['close'];
         $period['open'] += $info['open'];
         $period['close'] += $info['close'];
     }
     if ($week) {
         $rows[] = $this->formatBurnRow('Week To Date', $week);
         $rowc[] = 'week';
     }
     if ($month) {
         $rows[] = $this->formatBurnRow('Month To Date', $month);
         $rowc[] = 'month';
     }
     $rows[] = $this->formatBurnRow('All Time', $period);
     $rowc[] = 'aggregate';
     $rows = array_reverse($rows);
     $rowc = array_reverse($rowc);
     $table = new AphrontTableView($rows);
     $table->setRowClasses($rowc);
     $table->setHeaders(array('Period', 'Opened', 'Closed', 'Change'));
     $table->setColumnClasses(array('right wide', 'n', 'n', 'n'));
     if ($handle) {
         $header = "Task Burn Rate for Project " . $handle->renderLink();
         $caption = "<p>NOTE: This table reflects tasks <em>currently</em> in " . "the project. If a task was opened in the past but added to " . "the project recently, it is counted on the day it was " . "opened, not the day it was categorized. If a task was part " . "of this project in the past but no longer is, it is not " . "counted at all.</p>";
     } else {
         $header = "Task Burn Rate for All Tasks";
         $caption = null;
     }
     $panel = new AphrontPanelView();
     $panel->setHeader($header);
     $panel->setCaption($caption);
     $panel->appendChild($table);
     $tokens = array();
     if ($handle) {
         $tokens = array($handle->getPHID() => $handle->getFullName());
     }
     $filter = $this->renderReportFilters($tokens, $has_window = false);
     $id = celerity_generate_unique_node_id();
     $chart = phutil_render_tag('div', array('id' => $id, 'style' => 'border: 1px solid #6f6f6f; ' . 'margin: 1em 2em; ' . 'height: 400px; '), '');
     list($burn_x, $burn_y) = $this->buildSeries($data);
     require_celerity_resource('raphael-core');
     require_celerity_resource('raphael-g');
     require_celerity_resource('raphael-g-line');
     Javelin::initBehavior('line-chart', array('hardpoint' => $id, 'x' => array($burn_x), 'y' => array($burn_y), 'xformat' => 'epoch'));
     return array($filter, $chart, $panel);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $uri = $request->getStr('uri');
     $id = $request->getStr('id');
     $repositories = id(new PhabricatorRepository())->loadAll();
     if ($uri) {
         $uri_path = id(new PhutilURI($uri))->getPath();
         $matches = array();
         // Try to figure out which tracked repository this external lives in by
         // comparing repository metadata. We look for an exact match, but accept
         // a partial match.
         foreach ($repositories as $key => $repository) {
             $remote_uri = new PhutilURI($repository->getRemoteURI());
             if ($remote_uri->getPath() == $uri_path) {
                 $matches[$key] = 1;
             }
             if ($repository->getPublicRemoteURI() == $uri) {
                 $matches[$key] = 2;
             }
             if ($repository->getRemoteURI() == $uri) {
                 $matches[$key] = 3;
             }
         }
         arsort($matches);
         $best_match = head_key($matches);
         if ($best_match) {
             $repository = $repositories[$best_match];
             $redirect = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repository->getCallsign(), 'branch' => $repository->getDefaultBranch(), 'commit' => $id));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         }
     }
     // TODO: This is a rare query but does a table scan, add a key?
     $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('commitIdentifier = %s', $id);
     if (empty($commits)) {
         $desc = null;
         if ($uri) {
             $desc = phutil_escape_html($uri) . ', at ';
         }
         $desc .= phutil_escape_html($id);
         $content = id(new AphrontErrorView())->setTitle('Unknown External')->setSeverity(AphrontErrorView::SEVERITY_WARNING)->appendChild("<p>This external ({$desc}) does not appear in any tracked " . "repository. It may exist in an untracked repository that " . "Diffusion does not know about.</p>");
     } else {
         if (count($commits) == 1) {
             $commit = head($commits);
             $repo = $repositories[$commit->getRepositoryID()];
             $redirect = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repo->getCallsign(), 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
             return id(new AphrontRedirectResponse())->setURI($redirect);
         } else {
             $rows = array();
             foreach ($commits as $commit) {
                 $repo = $repositories[$commit->getRepositoryID()];
                 $href = DiffusionRequest::generateDiffusionURI(array('action' => 'browse', 'callsign' => $repo->getCallsign(), 'branch' => $repo->getDefaultBranch(), 'commit' => $commit->getCommitIdentifier()));
                 $rows[] = array(phutil_render_tag('a', array('href' => $href), phutil_escape_html('r' . $repo->getCallsign() . $commit->getCommitIdentifier())), phutil_escape_html($commit->loadCommitData()->getSummary()));
             }
             $table = new AphrontTableView($rows);
             $table->setHeaders(array('Commit', 'Description'));
             $table->setColumnClasses(array('pri', 'wide'));
             $content = new AphrontPanelView();
             $content->setHeader('Multiple Matching Commits');
             $content->setCaption('This external reference matches multiple known commits.');
             $content->appendChild($table);
         }
     }
     return $this->buildStandardPageResponse($content, array('title' => 'Unresolvable External'));
 }
 public function buildCommitPanel()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $phids = array($user->getPHID());
     $query = new PhabricatorAuditCommitQuery();
     $query->withAuthorPHIDs($phids);
     $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN);
     $query->needCommitData(true);
     $query->setLimit(10);
     $commits = $query->execute();
     if (!$commits) {
         return $this->renderMinipanel('No Problem Commits', 'No one has raised concerns with your commits.');
     }
     $view = new PhabricatorAuditCommitListView();
     $view->setCommits($commits);
     $view->setUser($user);
     $phids = $view->getRequiredHandlePHIDs();
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $view->setHandles($handles);
     $panel = new AphrontPanelView();
     $panel->setHeader('Problem Commits');
     $panel->setCaption('Commits which auditors have raised concerns about.');
     $panel->appendChild($view);
     $panel->addButton(phutil_render_tag('a', array('href' => '/audit/', 'class' => 'button grey'), "View Problem Commits »"));
     return $panel;
 }
 private function renderUploadPanel()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $limit_text = PhabricatorFileUploadView::renderUploadLimit();
     if ($this->useBasicUploader()) {
         $upload_panel = new PhabricatorFileUploadView();
         $upload_panel->setUser($user);
     } else {
         require_celerity_resource('files-css');
         $upload_id = celerity_generate_unique_node_id();
         $panel_id = celerity_generate_unique_node_id();
         $upload_panel = new AphrontPanelView();
         $upload_panel->setHeader('Upload Files');
         $upload_panel->setCaption($limit_text);
         $upload_panel->setCreateButton('Basic Uploader', $request->getRequestURI()->setQueryParam('basic_uploader', true));
         $upload_panel->setWidth(AphrontPanelView::WIDTH_FULL);
         $upload_panel->setID($panel_id);
         $upload_panel->appendChild(phutil_render_tag('div', array('id' => $upload_id, 'style' => 'display: none;', 'class' => 'files-drag-and-drop'), ''));
         Javelin::initBehavior('files-drag-and-drop', array('uri' => '/file/dropupload/', 'browseURI' => '/file/filter/my/', 'control' => $upload_id, 'target' => $panel_id, 'activatedClass' => 'aphront-panel-view-drag-and-drop'));
     }
     return $upload_panel;
 }
 private function buildMergesTable(PhabricatorRepositoryCommit $commit)
 {
     $drequest = $this->getDiffusionRequest();
     $limit = 50;
     $merge_query = DiffusionMergedCommitsQuery::newFromDiffusionRequest($drequest);
     $merge_query->setLimit($limit + 1);
     $merges = $merge_query->loadMergedCommits();
     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->setDiffusionRequest($drequest);
     $history_table->setHistory($merges);
     $phids = $history_table->getRequiredHandlePHIDs();
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $history_table->setHandles($handles);
     $panel = new AphrontPanelView();
     $panel->setHeader('Merged Changes');
     $panel->setCaption($caption);
     $panel->appendChild($history_table);
     return $panel;
 }
 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;
 }