protected function getBuiltinProfilePanels($object)
 {
     $viewer = $this->getViewer();
     $panels = array();
     $panels[] = $this->newPanel()->setBuiltinKey(self::PANEL_PROFILE)->setPanelKey(PhabricatorPeopleDetailsProfilePanel::PANELKEY);
     // TODO: Convert this into a proper panel type.
     $have_calendar = PhabricatorApplication::isClassInstalledForViewer('PhabricatorCalendarApplication', $viewer);
     if ($have_calendar) {
         $uri = urisprintf('/p/%s/calendar/', $object->getUsername());
         $panels[] = $this->newPanel()->setBuiltinKey('calendar')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'calendar')->setPanelProperty('name', pht('Calendar'))->setPanelProperty('uri', $uri);
     }
     $have_maniphest = PhabricatorApplication::isClassInstalledForViewer('PhabricatorManiphestApplication', $viewer);
     if ($have_maniphest) {
         $uri = urisprintf('/maniphest/?statuses=open()&assigned=%s#R', $object->getPHID());
         $panels[] = $this->newPanel()->setBuiltinKey('tasks')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'maniphest')->setPanelProperty('name', pht('Open Tasks'))->setPanelProperty('uri', $uri);
     }
     $have_differential = PhabricatorApplication::isClassInstalledForViewer('PhabricatorDifferentialApplication', $viewer);
     if ($have_differential) {
         $uri = urisprintf('/differential/?authors=%s#R', $object->getPHID());
         $panels[] = $this->newPanel()->setBuiltinKey('revisions')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'differential')->setPanelProperty('name', pht('Revisions'))->setPanelProperty('uri', $uri);
     }
     $have_diffusion = PhabricatorApplication::isClassInstalledForViewer('PhabricatorDiffusionApplication', $viewer);
     if ($have_diffusion) {
         $uri = urisprintf('/audit/?authors=%s#R', $object->getPHID());
         $panels[] = $this->newPanel()->setBuiltinKey('commits')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'diffusion')->setPanelProperty('name', pht('Commits'))->setPanelProperty('uri', $uri);
     }
     $panels[] = $this->newPanel()->setBuiltinKey(self::PANEL_MANAGE)->setPanelKey(PhabricatorPeopleManageProfilePanel::PANELKEY);
     return $panels;
 }
 public function buildIconNavView(PhabricatorProject $project)
 {
     $this->setProject($project);
     $viewer = $this->getViewer();
     $id = $project->getID();
     $picture = $project->getProfileImageURI();
     $name = $project->getName();
     $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute();
     if ($columns) {
         $board_icon = 'fa-columns';
     } else {
         $board_icon = 'fa-columns grey';
     }
     $nav = new AphrontSideNavFilterView();
     $nav->setIconNav(true);
     $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
     $nav->addIcon("profile/{$id}/", $name, null, $picture);
     $class = 'PhabricatorManiphestApplication';
     if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
         $phid = $project->getPHID();
         $nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
         $query_uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $phid);
         $nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
     }
     $nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o');
     $nav->addIcon("members/{$id}/", pht('Members'), 'fa-group');
     $nav->addIcon("details/{$id}/", pht('Edit Details'), 'fa-pencil');
     return $nav;
 }
 public static function getJumpResponse(PhabricatorUser $viewer, $jump)
 {
     $jump = trim($jump);
     $help_href = PhabricatorEnv::getDocLink('Jump Nav User Guide');
     $patterns = array('/^help/i' => 'uri:' . $help_href, '/^a$/i' => 'uri:/audit/', '/^f$/i' => 'uri:/feed/', '/^d$/i' => 'uri:/differential/', '/^r$/i' => 'uri:/diffusion/', '/^t$/i' => 'uri:/maniphest/', '/^p$/i' => 'uri:/project/', '/^u$/i' => 'uri:/people/', '/^p\\s+(.+)$/i' => 'project', '/^u\\s+(\\S+)$/i' => 'user', '/^task:\\s*(.+)/i' => 'create-task', '/^(?:s|symbol)\\s+(\\S+)/i' => 'find-symbol', '/^r\\s+(.+)$/i' => 'find-repository');
     foreach ($patterns as $pattern => $effect) {
         $matches = null;
         if (preg_match($pattern, $jump, $matches)) {
             if (!strncmp($effect, 'uri:', 4)) {
                 return id(new AphrontRedirectResponse())->setURI(substr($effect, 4));
             } else {
                 switch ($effect) {
                     case 'user':
                         return id(new AphrontRedirectResponse())->setURI('/p/' . $matches[1] . '/');
                     case 'project':
                         $project = self::findCloselyNamedProject($matches[1]);
                         if ($project) {
                             return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
                         } else {
                             $jump = $matches[1];
                         }
                         break;
                     case 'find-symbol':
                         $context = '';
                         $symbol = $matches[1];
                         $parts = array();
                         if (preg_match('/(.*)(?:\\.|::|->)(.*)/', $symbol, $parts)) {
                             $context = '&context=' . phutil_escape_uri($parts[1]);
                             $symbol = $parts[2];
                         }
                         return id(new AphrontRedirectResponse())->setURI("/diffusion/symbol/{$symbol}/?jump=true{$context}");
                     case 'find-repository':
                         $name = $matches[1];
                         $repositories = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withNameContains($name)->execute();
                         if (count($repositories) == 1) {
                             // Just one match, jump to repository.
                             $uri = '/diffusion/' . head($repositories)->getCallsign() . '/';
                         } else {
                             // More than one match, jump to search.
                             $uri = urisprintf('/diffusion/?order=name&name=%s', $name);
                         }
                         return id(new AphrontRedirectResponse())->setURI($uri);
                     case 'create-task':
                         return id(new AphrontRedirectResponse())->setURI('/maniphest/task/create/?title=' . phutil_escape_uri($matches[1]));
                     default:
                         throw new Exception("Unknown jump effect '{$effect}'!");
                 }
             }
         }
     }
     // If none of the patterns matched, look for an object by name.
     $objects = id(new PhabricatorObjectQuery())->setViewer($viewer)->withNames(array($jump))->execute();
     if (count($objects) == 1) {
         $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(mpull($objects, 'getPHID'))->executeOne();
         return id(new AphrontRedirectResponse())->setURI($handle->getURI());
     }
     return null;
 }
 protected function buildApplicationCrumbs()
 {
     $crumbs = parent::buildApplicationCrumbs();
     $user = $this->getUser();
     if ($user) {
         $crumbs->addTextCrumb($user->getUsername(), urisprintf('/p/%s/', $user->getUsername()));
     }
     return $crumbs;
 }
 protected function newNavigationMenuItems(PhabricatorProfilePanelConfiguration $config)
 {
     $user = $config->getProfileObject();
     $picture = $user->getProfileImageURI();
     $name = $user->getUsername();
     $href = urisprintf('/p/%s/', $user->getUsername());
     $item = $this->newItem()->setHref($href)->setName($name)->setProfileImage($picture);
     return array($item);
 }
 protected function getBuiltinProfilePanels($object)
 {
     $panels = array();
     $panels[] = $this->newPanel()->setBuiltinKey(PhabricatorProject::PANEL_PROFILE)->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY);
     $panels[] = $this->newPanel()->setBuiltinKey(PhabricatorProject::PANEL_WORKBOARD)->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY);
     // TODO: This is temporary.
     $uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $object->getPHID());
     $panels[] = $this->newPanel()->setBuiltinKey('tasks')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'maniphest')->setPanelProperty('name', pht('Open Tasks'))->setPanelProperty('uri', $uri);
     $panels[] = $this->newPanel()->setBuiltinKey(PhabricatorProject::PANEL_MEMBERS)->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
     return $panels;
 }
 public function processAddFactorForm(AphrontFormView $form, AphrontRequest $request, PhabricatorUser $user)
 {
     $totp_token_type = PhabricatorAuthTOTPKeyTemporaryTokenType::TOKENTYPE;
     $key = $request->getStr('totpkey');
     if (strlen($key)) {
         // If the user is providing a key, make sure it's a key we generated.
         // This raises the barrier to theoretical attacks where an attacker might
         // provide a known key (such attacks are already prevented by CSRF, but
         // this is a second barrier to overcome).
         // (We store and verify the hash of the key, not the key itself, to limit
         // how useful the data in the table is to an attacker.)
         $temporary_token = id(new PhabricatorAuthTemporaryTokenQuery())->setViewer($user)->withTokenResources(array($user->getPHID()))->withTokenTypes(array($totp_token_type))->withExpired(false)->withTokenCodes(array(PhabricatorHash::digest($key)))->executeOne();
         if (!$temporary_token) {
             // If we don't have a matching token, regenerate the key below.
             $key = null;
         }
     }
     if (!strlen($key)) {
         $key = self::generateNewTOTPKey();
         // Mark this key as one we generated, so the user is allowed to submit
         // a response for it.
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         id(new PhabricatorAuthTemporaryToken())->setTokenResource($user->getPHID())->setTokenType($totp_token_type)->setTokenExpires(time() + phutil_units('1 hour in seconds'))->setTokenCode(PhabricatorHash::digest($key))->save();
         unset($unguarded);
     }
     $code = $request->getStr('totpcode');
     $e_code = true;
     if ($request->getExists('totp')) {
         $okay = self::verifyTOTPCode($user, new PhutilOpaqueEnvelope($key), $code);
         if ($okay) {
             $config = $this->newConfigForUser($user)->setFactorName(pht('Mobile App (TOTP)'))->setFactorSecret($key);
             return $config;
         } else {
             if (!strlen($code)) {
                 $e_code = pht('Required');
             } else {
                 $e_code = pht('Invalid');
             }
         }
     }
     $form->addHiddenInput('totp', true);
     $form->addHiddenInput('totpkey', $key);
     $form->appendRemarkupInstructions(pht('First, download an authenticator application on your phone. Two ' . 'applications which work well are **Authy** and **Google ' . 'Authenticator**, but any other TOTP application should also work.'));
     $form->appendInstructions(pht('Launch the application on your phone, and add a new entry for ' . 'this Phabricator install. When prompted, scan the QR code or ' . 'manually enter the key shown below into the application.'));
     $prod_uri = new PhutilURI(PhabricatorEnv::getProductionURI('/'));
     $issuer = $prod_uri->getDomain();
     $uri = urisprintf('otpauth://totp/%s:%s?secret=%s&issuer=%s', $issuer, $user->getUsername(), $key, $issuer);
     $qrcode = $this->renderQRCode($uri);
     $form->appendChild($qrcode);
     $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Key'))->setValue(phutil_tag('strong', array(), $key)));
     $form->appendInstructions(pht('(If given an option, select that this key is "Time Based", not ' . '"Counter Based".)'));
     $form->appendInstructions(pht('After entering the key, the application should display a numeric ' . 'code. Enter that code below to confirm that you have configured ' . 'the authenticator correctly:'));
     $form->appendChild(id(new PHUIFormNumberControl())->setLabel(pht('TOTP Code'))->setName('totpcode')->setValue($code)->setError($e_code));
 }
 private function buildPackagesView(PhabricatorPackagesPublisher $publisher)
 {
     $viewer = $this->getViewer();
     $packages = id(new PhabricatorPackagesPackageQuery())->setViewer($viewer)->withPublisherPHIDs(array($publisher->getPHID()))->setLimit(25)->execute();
     $packages_list = id(new PhabricatorPackagesPackageListView())->setViewer($viewer)->setPackages($packages);
     $all_href = urisprintf('package/?publisher=%s#R', $publisher->getPHID());
     $all_href = $this->getApplicationURI($all_href);
     $view_all = id(new PHUIButtonView())->setTag('a')->setIcon('fa-search')->setText(pht('View All'))->setHref($all_href);
     $header = id(new PHUIHeaderView())->setHeader(pht('Packages'))->addActionLink($view_all);
     $packages_view = id(new PHUIObjectBoxView())->setHeader($header)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setObjectList($packages_list);
     return $packages_view;
 }
 private function buildNeedsTriagePanel(array $projects)
 {
     assert_instances_of($projects, 'PhabricatorProject');
     $needs_triage = PhabricatorEnv::getEnvConfig('maniphest.priorities.needs-triage');
     if (!$needs_triage) {
         return null;
     }
     $user = $this->getRequest()->getUser();
     if (!$user->isLoggedIn()) {
         return null;
     }
     if ($projects) {
         $task_query = id(new ManiphestTaskQuery())->setViewer($user)->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->withPriorities(array($needs_triage))->withEdgeLogicPHIDs(PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorQueryConstraint::OPERATOR_OR, mpull($projects, 'getPHID'))->needProjectPHIDs(true)->setLimit(10);
         $tasks = $task_query->execute();
     } else {
         $tasks = array();
     }
     if (!$tasks) {
         return $this->renderMiniPanel(pht('No "Needs Triage" Tasks'), pht('No tasks in projects you are a member of need triage.'));
     }
     $title = pht('Needs Triage');
     $href = urisprintf('/maniphest/?statuses=open()&priorities=%s&projects=projects(%s)#R', $needs_triage, $user->getPHID());
     $panel = new PHUIObjectBoxView();
     $panel->setHeader($this->renderSectionHeader($title, $href));
     $panel->setObjectList($this->buildTaskListView($tasks));
     return $panel;
 }
 public function testurisprintf()
 {
     $this->assertEqual('x.com?a=huh%3F', urisprintf('x.com?a=%s', 'huh?'));
     $this->assertEqual('/a/origin%252Fmaster/z/', urisprintf('/a/%p/z/', 'origin/master'));
     $this->assertEqual('y.com?%21&%23', vurisprintf('y.com?%s&%s', array('!', '#')));
 }
 public function buildSprintIconNavView(PhabricatorProject $project)
 {
     $viewer = $this->getViewer();
     $id = $project->getID();
     $picture = $project->getProfileImageURI();
     $name = $project->getName();
     $enable_phragile = PhabricatorEnv::getEnvConfig('sprint.enable-phragile');
     $phragile_base_uri = PhabricatorEnv::getEnvConfig('sprint.phragile-uri');
     $phragile_uri = new PhutilURI($phragile_base_uri . $id);
     $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute();
     if ($columns) {
         $board_icon = 'fa-columns';
     } else {
         $board_icon = 'fa-columns grey';
     }
     $nav = new AphrontSideNavFilterView();
     $nav->setIconNav(true);
     if ($this->isSprint($project) !== false) {
         $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
         $nav->addIcon("profile/{$id}/", $name, null, $picture, null);
         $nav->addIcon("burn/{$id}/", pht('Burndown'), 'fa-fire', null, null);
         if ($enable_phragile) {
             $nav->addIcon("sprints/{$id}/", pht('Phragile'), 'fa-pie-chart', null, $phragile_uri);
         }
         $nav->addIcon("board/{$id}/", pht('Sprint Board'), $board_icon, null, null);
         $nav->addIcon('.', pht('Sprint List'), 'fa-bar-chart', null, null);
     } else {
         $nav->setBaseURI(new PhutilURI($this->getProjectsURI()));
         $nav->addIcon("profile/{$id}/", $name, null, $picture);
         $nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
     }
     $class = 'PhabricatorManiphestApplication';
     if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
         $phid = $project->getPHID();
         $query_uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $phid);
         $nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
     }
     $nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o', null, null);
     $nav->addIcon("members/{$id}/", pht('Members'), 'fa-group', null, null);
     $nav->addIcon("details/{$id}/", pht('Edit Details'), 'fa-pencil', null, null);
     return $nav;
 }
 private function renderTasksPage(PhabricatorProject $project)
 {
     $user = $this->getRequest()->getUser();
     $query = id(new ManiphestTaskQuery())->setViewer($user)->withAnyProjects(array($project->getPHID()))->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)->setLimit(10);
     $tasks = $query->execute();
     $phids = mpull($tasks, 'getOwnerPHID');
     $phids = array_merge($phids, array_mergev(mpull($tasks, 'getProjectPHIDs')));
     $phids = array_filter($phids);
     $handles = $this->loadViewerHandles($phids);
     $task_list = new ManiphestTaskListView();
     $task_list->setUser($user);
     $task_list->setTasks($tasks);
     $task_list->setHandles($handles);
     $phid = $project->getPHID();
     $view_uri = urisprintf('/maniphest/?statuses=%s&allProjects=%s#R', implode(',', ManiphestTaskStatus::getOpenStatusConstants()), $phid);
     $create_uri = '/maniphest/task/create/?projects=' . $phid;
     $icon = id(new PHUIIconView())->setIconFont('fa-list');
     $button_view = id(new PHUIButtonView())->setTag('a')->setText(pht('View All'))->setHref($view_uri)->setIcon($icon);
     $icon_new = id(new PHUIIconView())->setIconFont('fa-plus');
     $button_add = id(new PHUIButtonView())->setTag('a')->setText(pht('New Task'))->setHref($create_uri)->setIcon($icon_new);
     $header = id(new PHUIHeaderView())->setHeader(pht('Open Tasks'))->addActionLink($button_add)->addActionLink($button_view);
     $content = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($task_list);
     return $content;
 }
 private function verifyRemotePermissions($viewer, $revision, $repository)
 {
     $github_user = $this->account->getUsername();
     $github_repo = $this->findGitHubRepo($repository);
     $uri = urisprintf('https://api.github.com/repos/%s/collaborators/%s', $github_repo, $github_user);
     $uri = new PhutilURI($uri);
     $uri->setQueryParam('access_token', $this->getAccessToken());
     list($status, $body, $headers) = id(new HTTPSFuture($uri))->resolve();
     // Likely status codes:
     // 204 No Content: Has permissions. Token might be too weak.
     // 404 Not Found: Not a collaborator.
     // 401 Unauthorized: Token is bad/revoked.
     $no_permission = $status->getStatusCode() == 404;
     if ($no_permission) {
         throw new Exception(pht("You don't have permission to push to this repository. " . "Push permissions for this repository are managed on GitHub."));
     }
     $scopes = BaseHTTPFuture::getHeader($headers, 'X-OAuth-Scopes');
     if (strpos($scopes, 'public_repo') === false) {
         $provider_key = $this->provider->getProviderKey();
         $refresh_token_uri = new PhutilURI("/auth/refresh/{$provider_key}/");
         $refresh_token_uri->setQueryParam('scope', 'public_repo');
         return id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Stronger token needed'))->appendChild(pht('In order to complete this action, you need a ' . 'stronger GitHub token.'))->setSubmitURI($refresh_token_uri)->addCancelButton('/D' . $revision->getId())->setDisableWorkflowOnSubmit(true)->addSubmitButton(pht('Refresh Account Link'));
     }
 }
 private function buildCalendarDayView(PhabricatorUser $user)
 {
     $viewer = $this->getViewer();
     $class = 'PhabricatorCalendarApplication';
     if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
         return null;
     }
     $midnight = PhabricatorTime::getTodayMidnightDateTime($viewer);
     $week_end = clone $midnight;
     $week_end = $week_end->modify('+3 days');
     $range_start = $midnight->format('U');
     $range_end = $week_end->format('U');
     $query = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withDateRange($range_start, $range_end)->withInvitedPHIDs(array($user->getPHID()))->withIsCancelled(false);
     $statuses = $query->execute();
     $phids = mpull($statuses, 'getUserPHID');
     $events = array();
     foreach ($statuses as $status) {
         $viewer_is_invited = $status->getIsUserInvited($user->getPHID());
         $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $status, PhabricatorPolicyCapability::CAN_EDIT);
         $event = id(new AphrontCalendarEventView())->setCanEdit($can_edit)->setEventID($status->getID())->setEpochRange($status->getDateFrom(), $status->getDateTo())->setIsAllDay($status->getIsAllDay())->setIcon($status->getIcon())->setViewerIsInvited($viewer_is_invited)->setName($status->getName())->setURI($status->getURI());
         $events[] = $event;
     }
     $events = msort($events, 'getEpochStart');
     $day_view = id(new PHUICalendarWeekView())->setViewer($viewer)->setView('week')->setEvents($events)->setWeekLength(3)->render();
     $header = id(new PHUIHeaderView())->setHeader(pht('Calendar'))->setHref(urisprintf('/calendar/?invitedPHIDs=%s#R', $user->getPHID()));
     $box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($day_view)->setBackground(PHUIObjectBoxView::GREY);
     return $box;
 }
 public function buildIconNavView(PhabricatorProject $project)
 {
     $this->setProject($project);
     $viewer = $this->getViewer();
     $id = $project->getID();
     $picture = $project->getProfileImageURI();
     $name = $project->getName();
     $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute();
     if ($columns) {
         $board_icon = 'fa-columns';
     } else {
         $board_icon = 'fa-columns grey';
     }
     $nav = new AphrontSideNavFilterView();
     $nav->setIconNav(true);
     $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
     $nav->addIcon("profile/{$id}/", $name, null, $picture);
     $class = 'PhabricatorManiphestApplication';
     if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
         $phid = $project->getPHID();
         $nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
         $query_uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $phid);
         $nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
     }
     $nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o');
     $nav->addIcon("members/{$id}/", pht('Members'), 'fa-group');
     if (false && PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
         if ($project->supportsSubprojects()) {
             $subprojects_icon = 'fa-sitemap';
         } else {
             $subprojects_icon = 'fa-sitemap grey';
         }
         $key = PhabricatorProjectIconSet::getMilestoneIconKey();
         $milestones_icon = PhabricatorProjectIconSet::getIconIcon($key);
         if (!$project->supportsMilestones()) {
             $milestones_icon = "{$milestones_icon} grey";
         }
         $nav->addIcon("subprojects/{$id}/", pht('Subprojects'), $subprojects_icon);
         $nav->addIcon("milestones/{$id}/", pht('Milestones'), $milestones_icon);
     }
     return $nav;
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($id))->needSubscriberPHIDs(true)->executeOne();
     if (!$task) {
         return new Aphront404Response();
     }
     $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW);
     $field_list->setViewer($viewer)->readFieldsFromStorage($task);
     $edit_engine = id(new ManiphestEditEngine())->setViewer($viewer)->setTargetObject($task);
     $edge_types = array(ManiphestTaskHasCommitEdgeType::EDGECONST, ManiphestTaskHasRevisionEdgeType::EDGECONST, ManiphestTaskHasMockEdgeType::EDGECONST, PhabricatorObjectMentionedByObjectEdgeType::EDGECONST, PhabricatorObjectMentionsObjectEdgeType::EDGECONST);
     $phid = $task->getPHID();
     $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes($edge_types);
     $edges = idx($query->execute(), $phid);
     $phids = array_fill_keys($query->getDestinationPHIDs(), true);
     if ($task->getOwnerPHID()) {
         $phids[$task->getOwnerPHID()] = true;
     }
     $phids[$task->getAuthorPHID()] = true;
     $phids = array_keys($phids);
     $handles = $viewer->loadHandles($phids);
     $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery());
     $monogram = $task->getMonogram();
     $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($monogram)->setBorder(true);
     $header = $this->buildHeaderView($task);
     $details = $this->buildPropertyView($task, $field_list, $edges, $handles);
     $description = $this->buildDescriptionView($task);
     $curtain = $this->buildCurtain($task, $edit_engine);
     $title = pht('%s %s', $monogram, $task->getTitle());
     $comment_view = $edit_engine->buildEditEngineCommentView($task);
     $timeline->setQuoteRef($monogram);
     $comment_view->setTransactionTimeline($timeline);
     $related_tabs = array();
     $graph_menu = null;
     $graph_limit = 100;
     $task_graph = id(new ManiphestTaskGraph())->setViewer($viewer)->setSeedPHID($task->getPHID())->setLimit($graph_limit)->loadGraph();
     if (!$task_graph->isEmpty()) {
         $parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
         $subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
         $parent_map = $task_graph->getEdges($parent_type);
         $subtask_map = $task_graph->getEdges($subtask_type);
         $parent_list = idx($parent_map, $task->getPHID(), array());
         $subtask_list = idx($subtask_map, $task->getPHID(), array());
         $has_parents = (bool) $parent_list;
         $has_subtasks = (bool) $subtask_list;
         $search_text = pht('Search...');
         // First, get a count of direct parent tasks and subtasks. If there
         // are too many of these, we just don't draw anything. You can use
         // the search button to browse tasks with the search UI instead.
         $direct_count = count($parent_list) + count($subtask_list);
         if ($direct_count > $graph_limit) {
             $message = pht('Task graph too large to display (this task is directly connected ' . 'to more than %s other tasks). Use %s to explore connected tasks.', $graph_limit, phutil_tag('strong', array(), $search_text));
             $message = phutil_tag('em', array(), $message);
             $graph_table = id(new PHUIPropertyListView())->addTextContent($message);
         } else {
             // If there aren't too many direct tasks, but there are too many total
             // tasks, we'll only render directly connected tasks.
             if ($task_graph->isOverLimit()) {
                 $task_graph->setRenderOnlyAdjacentNodes(true);
             }
             $graph_table = $task_graph->newGraphTable();
         }
         $parents_uri = urisprintf('/?subtaskIDs=%d#R', $task->getID());
         $parents_uri = $this->getApplicationURI($parents_uri);
         $subtasks_uri = urisprintf('/?parentIDs=%d#R', $task->getID());
         $subtasks_uri = $this->getApplicationURI($subtasks_uri);
         $dropdown_menu = id(new PhabricatorActionListView())->setViewer($viewer)->addAction(id(new PhabricatorActionView())->setHref($parents_uri)->setName(pht('Search Parent Tasks'))->setDisabled(!$has_parents)->setIcon('fa-chevron-circle-up'))->addAction(id(new PhabricatorActionView())->setHref($subtasks_uri)->setName(pht('Search Subtasks'))->setDisabled(!$has_subtasks)->setIcon('fa-chevron-circle-down'));
         $graph_menu = id(new PHUIButtonView())->setTag('a')->setIcon('fa-search')->setText($search_text)->setDropdownMenu($dropdown_menu);
         $related_tabs[] = id(new PHUITabView())->setName(pht('Task Graph'))->setKey('graph')->appendChild($graph_table);
     }
     $related_tabs[] = $this->newMocksTab($task, $query);
     $related_tabs[] = $this->newMentionsTab($task, $query);
     $tab_view = null;
     $related_tabs = array_filter($related_tabs);
     if ($related_tabs) {
         $tab_group = new PHUITabGroupView();
         foreach ($related_tabs as $tab) {
             $tab_group->addTab($tab);
         }
         $related_header = id(new PHUIHeaderView())->setHeader(pht('Related Objects'));
         if ($graph_menu) {
             $related_header->addActionLink($graph_menu);
         }
         $tab_view = id(new PHUIObjectBoxView())->setHeader($related_header)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->addTabGroup($tab_group);
     }
     $view = id(new PHUITwoColumnView())->setHeader($header)->setCurtain($curtain)->setMainColumn(array($tab_view, $timeline, $comment_view))->addPropertySection(pht('Description'), $description)->addPropertySection(pht('Details'), $details);
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setPageObjectPHIDs(array($task->getPHID()))->appendChild($view);
 }
 private function buildCalendarDayView(PhabricatorUser $user)
 {
     $viewer = $this->getViewer();
     $class = 'PhabricatorCalendarApplication';
     if (!PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
         return null;
     }
     $midnight = PhabricatorTime::getTodayMidnightDateTime($viewer);
     $week_end = clone $midnight;
     $week_end = $week_end->modify('+3 days');
     $range_start = $midnight->format('U');
     $range_end = $week_end->format('U');
     $events = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withDateRange($range_start, $range_end)->withInvitedPHIDs(array($user->getPHID()))->withIsCancelled(false)->needRSVPs(array($viewer->getPHID()))->execute();
     $event_views = array();
     foreach ($events as $event) {
         $viewer_is_invited = $event->isRSVPInvited($viewer->getPHID());
         $can_edit = PhabricatorPolicyFilter::hasCapability($viewer, $event, PhabricatorPolicyCapability::CAN_EDIT);
         $epoch_min = $event->getStartDateTimeEpoch();
         $epoch_max = $event->getEndDateTimeEpoch();
         $event_view = id(new AphrontCalendarEventView())->setCanEdit($can_edit)->setEventID($event->getID())->setEpochRange($epoch_min, $epoch_max)->setIsAllDay($event->getIsAllDay())->setIcon($event->getIcon())->setViewerIsInvited($viewer_is_invited)->setName($event->getName())->setDatetimeSummary($event->renderEventDate($viewer, true))->setURI($event->getURI());
         $event_views[] = $event_view;
     }
     $event_views = msort($event_views, 'getEpochStart');
     $day_view = id(new PHUICalendarWeekView())->setViewer($viewer)->setView('week')->setEvents($event_views)->setWeekLength(3)->render();
     $header = id(new PHUIHeaderView())->setHeader(pht('Calendar'))->setHref(urisprintf('/calendar/?invited=%s#R', $user->getUsername()));
     $box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($day_view)->addClass('calendar-profile-box')->setBackground(PHUIObjectBoxView::GREY);
     return $box;
 }
示例#18
0
 public static function getReadOnlyURI()
 {
     return urisprintf('/readonly/%s/', self::getReadOnlyReason());
 }
 private function buildNeedsTriagePanel(array $projects)
 {
     assert_instances_of($projects, 'PhabricatorProject');
     $needs_triage = PhabricatorEnv::getEnvConfig('maniphest.priorities.needs-triage');
     if (!$needs_triage) {
         return null;
     }
     $user = $this->getRequest()->getUser();
     if (!$user->isLoggedIn()) {
         return null;
     }
     if ($projects) {
         $task_query = id(new ManiphestTaskQuery())->setViewer($user)->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->withPriorities(array($needs_triage))->withAnyProjects(mpull($projects, 'getPHID'))->setLimit(10);
         $tasks = $task_query->execute();
     } else {
         $tasks = array();
     }
     if (!$tasks) {
         return $this->renderMiniPanel('No "Needs Triage" Tasks', hsprintf('No tasks in <a href="/project/">projects you are a member of</a> ' . 'need triage.'));
     }
     $title = pht('Needs Triage');
     $href = urisprintf('/maniphest/?statuses=%s&priorities=%s&userProjects=%s#R', implode(',', ManiphestTaskStatus::getOpenStatusConstants()), $needs_triage, $user->getPHID());
     $panel = new AphrontPanelView();
     $panel->setHeader($this->renderSectionHeader($title, $href));
     $panel->appendChild($this->buildTaskListView($tasks));
     $panel->setNoBackground();
     return $panel;
 }
 public function getBuiltinProfilePanels()
 {
     $panels = array();
     $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()->setBuiltinKey(self::PANEL_PROFILE)->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY);
     $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()->setBuiltinKey(self::PANEL_WORKBOARD)->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY);
     // TODO: This is temporary.
     $uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $this->getPHID());
     $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()->setBuiltinKey('tasks')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'maniphest')->setPanelProperty('name', pht('Open Tasks'))->setPanelProperty('uri', $uri);
     // TODO: This is temporary.
     $id = $this->getID();
     $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()->setBuiltinKey('feed')->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY)->setPanelProperty('icon', 'feed')->setPanelProperty('name', pht('Feed'))->setPanelProperty('uri', "/project/feed/{$id}/");
     $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin()->setBuiltinKey(self::PANEL_MEMBERS)->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY);
     return $panels;
 }