diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php index 245cb3d8a9..19131f4e31 100644 --- a/src/applications/base/controller/PhabricatorController.php +++ b/src/applications/base/controller/PhabricatorController.php @@ -1,329 +1,340 @@ shouldAllowPublic()) { return false; } return true; } public function shouldRequireAdmin() { return false; } public function shouldRequireEnabledUser() { return true; } public function shouldAllowPublic() { return false; } public function shouldRequireEmailVerification() { $need_verify = PhabricatorUserEmail::isEmailVerificationRequired(); $need_login = $this->shouldRequireLogin(); return ($need_login && $need_verify); } final public function willBeginExecution() { $request = $this->getRequest(); $user = new PhabricatorUser(); $phusr = $request->getCookie('phusr'); $phsid = $request->getCookie('phsid'); if (strlen($phusr) && $phsid) { $info = queryfx_one( $user->establishConnection('r'), 'SELECT u.* FROM %T u JOIN %T s ON u.phid = s.userPHID AND s.type LIKE %> AND s.sessionKey = %s', $user->getTableName(), 'phabricator_session', 'web-', PhabricatorHash::digest($phsid)); if ($info) { $user->loadFromArray($info); } } $translation = $user->getTranslation(); if ($translation && $translation != PhabricatorEnv::getEnvConfig('translation.provider')) { $translation = newv($translation, array()); PhutilTranslator::getInstance() ->setLanguage($translation->getLanguage()) ->addTranslations($translation->getTranslations()); } $request->setUser($user); if ($user->getIsDisabled() && $this->shouldRequireEnabledUser()) { $disabled_user_controller = new PhabricatorDisabledUserController( $request); return $this->delegateToController($disabled_user_controller); } $event = new PhabricatorEvent( PhabricatorEventType::TYPE_CONTROLLER_CHECKREQUEST, array( 'request' => $request, 'controller' => $this, )); $event->setUser($user); PhutilEventEngine::dispatchEvent($event); $checker_controller = $event->getValue('controller'); if ($checker_controller != $this) { return $this->delegateToController($checker_controller); } $preferences = $user->loadPreferences(); if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) { $dark_console = PhabricatorUserPreferences::PREFERENCE_DARK_CONSOLE; if ($preferences->getPreference($dark_console) || PhabricatorEnv::getEnvConfig('darkconsole.always-on')) { $console = new DarkConsoleCore(); $request->getApplicationConfiguration()->setConsole($console); } } if ($this->shouldRequireLogin() && !$user->getPHID()) { $login_controller = new PhabricatorAuthStartController($request); $this->setCurrentApplication( PhabricatorApplication::getByClass('PhabricatorApplicationAuth')); return $this->delegateToController($login_controller); } if ($this->shouldRequireEmailVerification()) { $email = $user->loadPrimaryEmail(); if (!$email) { throw new Exception( "No primary email address associated with this account!"); } if (!$email->getIsVerified()) { $verify_controller = new PhabricatorMustVerifyEmailController($request); return $this->delegateToController($verify_controller); } } if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) { return new Aphront403Response(); } + // If the user doesn't have access to the application, don't let them use + // any of its controllers. We query the application in order to generate + // a policy exception if the viewer doesn't have permission. + $application = $this->getCurrentApplication(); + if ($application) { + id(new PhabricatorApplicationQuery()) + ->setViewer($user) + ->withPHIDs(array($application->getPHID())) + ->executeOne(); + } + } public function buildStandardPageView() { $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->setController($this); return $view; } public function buildStandardPageResponse($view, array $data) { $page = $this->buildStandardPageView(); $page->appendChild($view); $response = new AphrontWebpageResponse(); $response->setContent($page->render()); return $response; } public function getApplicationURI($path = '') { if (!$this->getCurrentApplication()) { throw new Exception("No application!"); } return $this->getCurrentApplication()->getApplicationURI($path); } public function buildApplicationPage($view, array $options) { $page = $this->buildStandardPageView(); $title = PhabricatorEnv::getEnvConfig('phabricator.serious-business') ? 'Phabricator' : pht('Bacon Ice Cream for Breakfast'); $application = $this->getCurrentApplication(); $page->setTitle(idx($options, 'title', $title)); if ($application) { $page->setApplicationName($application->getName()); if ($application->getTitleGlyph()) { $page->setGlyph($application->getTitleGlyph()); } } if (!($view instanceof AphrontSideNavFilterView)) { $nav = new AphrontSideNavFilterView(); $nav->appendChild($view); $view = $nav; } $user = $this->getRequest()->getUser(); $view->setUser($user); $page->appendChild($view); $object_phids = idx($options, 'pageObjects', array()); if ($object_phids) { $page->appendPageObjects($object_phids); foreach ($object_phids as $object_phid) { PhabricatorFeedStoryNotification::updateObjectNotificationViews( $user, $object_phid); } } if (idx($options, 'device')) { $page->setDeviceReady(true); } $page->setShowChrome(idx($options, 'chrome', true)); $application_menu = $this->buildApplicationMenu(); if ($application_menu) { $page->setApplicationMenu($application_menu); } $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } public function didProcessRequest($response) { $request = $this->getRequest(); $response->setRequest($request); $seen = array(); while ($response instanceof AphrontProxyResponse) { $hash = spl_object_hash($response); if (isset($seen[$hash])) { $seen[] = get_class($response); throw new Exception( "Cycle while reducing proxy responses: ". implode(' -> ', $seen)); } $seen[$hash] = get_class($response); $response = $response->reduceProxyResponse(); } if ($response instanceof AphrontDialogResponse) { if (!$request->isAjax()) { $view = new PhabricatorStandardPageView(); $view->setRequest($request); $view->setController($this); $view->appendChild(hsprintf( '
%s
', $response->buildResponseString())); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } else { $response->getDialog()->setIsStandalone(true); return id(new AphrontAjaxResponse()) ->setContent(array( 'dialog' => $response->buildResponseString(), )); } } else if ($response instanceof AphrontRedirectResponse) { if ($request->isAjax()) { return id(new AphrontAjaxResponse()) ->setContent( array( 'redirect' => $response->getURI(), )); } } return $response; } protected function getHandle($phid) { if (empty($this->handles[$phid])) { throw new Exception( "Attempting to access handle which wasn't loaded: {$phid}"); } return $this->handles[$phid]; } protected function loadHandles(array $phids) { $phids = array_filter($phids); $this->handles = $this->loadViewerHandles($phids); return $this; } protected function getLoadedHandles() { return $this->handles; } protected function loadViewerHandles(array $phids) { return id(new PhabricatorHandleQuery()) ->setViewer($this->getRequest()->getUser()) ->withPHIDs($phids) ->execute(); } /** * Render a list of links to handles, identified by PHIDs. The handles must * already be loaded. * * @param list List of PHIDs to render links to. * @param string Style, one of "\n" (to put each item on its own line) * or "," (to list items inline, separated by commas). * @return string Rendered list of handle links. */ protected function renderHandlesForPHIDs(array $phids, $style = "\n") { $style_map = array( "\n" => phutil_tag('br'), ',' => ', ', ); if (empty($style_map[$style])) { throw new Exception("Unknown handle list style '{$style}'!"); } return implode_selected_handle_links($style_map[$style], $this->getLoadedHandles(), $phids); } protected function buildApplicationMenu() { return null; } protected function buildApplicationCrumbs() { $crumbs = array(); $application = $this->getCurrentApplication(); if ($application) { $sprite = $application->getIconName(); if (!$sprite) { $sprite = 'application'; } $crumbs[] = id(new PhabricatorCrumbView()) ->setHref($this->getApplicationURI()) ->setIcon($sprite); } $view = new PhabricatorCrumbsView(); foreach ($crumbs as $crumb) { $view->addCrumb($crumb); } return $view; } } diff --git a/src/applications/directory/controller/PhabricatorDirectoryController.php b/src/applications/directory/controller/PhabricatorDirectoryController.php index bdf85b43db..07df8c8589 100644 --- a/src/applications/directory/controller/PhabricatorDirectoryController.php +++ b/src/applications/directory/controller/PhabricatorDirectoryController.php @@ -1,176 +1,179 @@ buildStandardPageView(); $page->setBaseURI('/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9A\x92"); $page->appendChild($view); $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } public function buildNav() { $user = $this->getRequest()->getUser(); $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/')); - $applications = PhabricatorApplication::getAllInstalledApplications(); + $applications = id(new PhabricatorApplicationQuery()) + ->setViewer($user) + ->withInstalled(true) + ->execute(); foreach ($applications as $key => $application) { if (!$application->shouldAppearInLaunchView()) { // Remove hidden applications (usually internal stuff). unset($applications[$key]); } $invisible = PhabricatorApplication::TILE_INVISIBLE; if ($application->getDefaultTileDisplay($user) == $invisible) { // Remove invisible applications (e.g., admin apps for non-admins). unset($applications[$key]); } } $status = array(); foreach ($applications as $key => $application) { $status[get_class($application)] = $application->loadStatus($user); } $tile_groups = array(); $prefs = $user->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_APP_TILES, array()); foreach ($applications as $key => $application) { $display = idx( $prefs, get_class($application), $application->getDefaultTileDisplay($user)); $tile_groups[$display][] = $application; } $tile_groups = array_select_keys( $tile_groups, array( PhabricatorApplication::TILE_FULL, PhabricatorApplication::TILE_SHOW, PhabricatorApplication::TILE_HIDE, )); foreach ($tile_groups as $tile_display => $tile_group) { if (!$tile_group) { continue; } $is_small_tiles = ($tile_display == PhabricatorApplication::TILE_SHOW) || ($tile_display == PhabricatorApplication::TILE_HIDE); if ($is_small_tiles) { $groups = PhabricatorApplication::getApplicationGroups(); $tile_group = mgroup($tile_group, 'getApplicationGroup'); $tile_group = array_select_keys($tile_group, array_keys($groups)); } else { $tile_group = array($tile_group); } $is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE); if ($is_hide) { $show_item_id = celerity_generate_unique_node_id(); $hide_item_id = celerity_generate_unique_node_id(); $show_item = id(new PHUIListItemView()) ->setName(pht('Show More Applications')) ->setHref('#') ->addSigil('reveal-content') ->setID($show_item_id); $hide_item = id(new PHUIListItemView()) ->setName(pht('Show Fewer Applications')) ->setHref('#') ->setStyle('display: none') ->setID($hide_item_id) ->addSigil('reveal-content'); $nav->addMenuItem($show_item); $tile_ids = array($hide_item_id); } foreach ($tile_group as $group => $application_list) { $tiles = array(); foreach ($application_list as $key => $application) { $tile = id(new PhabricatorApplicationLaunchView()) ->setApplication($application) ->setApplicationStatus( idx($status, get_class($application), array())) ->setUser($user); if ($tile_display == PhabricatorApplication::TILE_FULL) { $tile->setFullWidth(true); } $tiles[] = $tile; } if ($is_small_tiles) { while (count($tiles) % 3) { $tiles[] = id(new PhabricatorApplicationLaunchView()); } $label = id(new PHUIListItemView()) ->setType(PHUIListItemView::TYPE_LABEL) ->setName($groups[$group]); if ($is_hide) { $label_id = celerity_generate_unique_node_id(); $attrs = array(); $label->setStyle('display: none;'); $label->setID($label_id); $tile_ids[] = $label_id; } $nav->addMenuItem($label); } $group_id = celerity_generate_unique_node_id(); $tile_ids[] = $group_id; $nav->addCustomBlock( phutil_tag( 'div', array( 'class' => 'application-tile-group', 'id' => $group_id, 'style' => ($is_hide ? 'display: none' : null), ), mpull($tiles, 'render'))); } if ($is_hide) { Javelin::initBehavior('phabricator-reveal-content'); $show_item->setMetadata( array( 'showIDs' => $tile_ids, 'hideIDs' => array($show_item_id), )); $hide_item->setMetadata( array( 'showIDs' => array($show_item_id), 'hideIDs' => $tile_ids, )); $nav->addMenuItem($hide_item); } } $nav->addFilter( '', pht('Customize Applications...'), '/settings/panel/home/'); $nav->addClass('phabricator-side-menu-home'); $nav->selectFilter(null); return $nav; } }