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; }
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; }