Modernize most Conduit console interfaces
Summary:
Ref T603. Ref T2625.
Long chain of "doing the right thing" here: I want to clean this up, so I can clean up the Conduit logs, so I can add a setup issue for deprecated method calls, so I can remove deprecated methods, so I can get rid of `DifferentialRevisionListData`, so I can make Differntial policy-aware.
Adds modern infrastructure and UI to all of the Conduit interfaces (except only partially for the logs, that will be the next diff).
Test Plan:
{F48201}
{F48202}
{F48203}
{F48204}
{F48206}
This will get further updates in the next diff:
{F48205}
Reviewers: btrahan, chad
Reviewed By: chad
CC: aran
Maniphest Tasks: T603, T2625
Differential Revision: https://secure.phabricator.com/D6331
			
			
This commit is contained in:
		| @@ -921,6 +921,8 @@ phutil_register_library_map(array( | ||||
|     'PhabricatorConduitListController' => 'applications/conduit/controller/PhabricatorConduitListController.php', | ||||
|     'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php', | ||||
|     'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php', | ||||
|     'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php', | ||||
|     'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php', | ||||
|     'PhabricatorConduitTokenController' => 'applications/conduit/controller/PhabricatorConduitTokenController.php', | ||||
|     'PhabricatorConfigAllController' => 'applications/config/controller/PhabricatorConfigAllController.php', | ||||
|     'PhabricatorConfigController' => 'applications/config/controller/PhabricatorConfigController.php', | ||||
| @@ -2009,6 +2011,11 @@ phutil_register_library_map(array( | ||||
|     'CelerityResourceController' => 'PhabricatorController', | ||||
|     'CelerityResourceGraph' => 'AbstractDirectedGraph', | ||||
|     'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase', | ||||
|     'ConduitAPIMethod' => | ||||
|     array( | ||||
|       0 => 'Phobject', | ||||
|       1 => 'PhabricatorPolicyInterface', | ||||
|     ), | ||||
|     'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod', | ||||
|     'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method', | ||||
|     'ConduitAPI_audit_Method' => 'ConduitAPIMethod', | ||||
| @@ -2807,9 +2814,15 @@ phutil_register_library_map(array( | ||||
|     'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', | ||||
|     'PhabricatorConduitController' => 'PhabricatorController', | ||||
|     'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', | ||||
|     'PhabricatorConduitListController' => 'PhabricatorConduitController', | ||||
|     'PhabricatorConduitListController' => | ||||
|     array( | ||||
|       0 => 'PhabricatorConduitController', | ||||
|       1 => 'PhabricatorApplicationSearchResultsControllerInterface', | ||||
|     ), | ||||
|     'PhabricatorConduitLogController' => 'PhabricatorConduitController', | ||||
|     'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', | ||||
|     'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', | ||||
|     'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine', | ||||
|     'PhabricatorConduitTokenController' => 'PhabricatorConduitController', | ||||
|     'PhabricatorConfigAllController' => 'PhabricatorConfigController', | ||||
|     'PhabricatorConfigController' => 'PhabricatorController', | ||||
|   | ||||
| @@ -38,7 +38,7 @@ final class PhabricatorApplicationConduit extends PhabricatorApplication { | ||||
|   public function getRoutes() { | ||||
|     return array( | ||||
|       '/conduit/' => array( | ||||
|         '' => 'PhabricatorConduitListController', | ||||
|         '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorConduitListController', | ||||
|         'method/(?P<method>[^/]+)/' => 'PhabricatorConduitConsoleController', | ||||
|         'log/' => 'PhabricatorConduitLogController', | ||||
|         'log/view/(?P<view>[^/]+)/' => 'PhabricatorConduitLogController', | ||||
|   | ||||
| @@ -354,6 +354,7 @@ final class PhabricatorConduitAPIController | ||||
|     } | ||||
|  | ||||
|     $param_table = new AphrontTableView($param_rows); | ||||
|     $param_table->setDeviceReadyTable(true); | ||||
|     $param_table->setColumnClasses( | ||||
|       array( | ||||
|         'header', | ||||
| @@ -369,6 +370,7 @@ final class PhabricatorConduitAPIController | ||||
|     } | ||||
|  | ||||
|     $result_table = new AphrontTableView($result_rows); | ||||
|     $result_table->setDeviceReadyTable(true); | ||||
|     $result_table->setColumnClasses( | ||||
|       array( | ||||
|         'header', | ||||
| @@ -383,13 +385,36 @@ final class PhabricatorConduitAPIController | ||||
|     $result_panel->setHeader('Method Result'); | ||||
|     $result_panel->appendChild($result_table); | ||||
|  | ||||
|     return $this->buildStandardPageResponse( | ||||
|     $param_head = id(new PhabricatorHeaderView()) | ||||
|       ->setHeader(pht('Method Parameters')); | ||||
|  | ||||
|     $result_head = id(new PhabricatorHeaderView()) | ||||
|       ->setHeader(pht('Method Result')); | ||||
|  | ||||
|     $method_uri = $this->getApplicationURI('method/'.$method.'/'); | ||||
|  | ||||
|     $crumbs = $this->buildApplicationCrumbs(); | ||||
|     $crumbs | ||||
|       ->addCrumb( | ||||
|         id(new PhabricatorCrumbView()) | ||||
|           ->setName($method) | ||||
|           ->setHref($method_uri)) | ||||
|       ->addCrumb( | ||||
|         id(new PhabricatorCrumbView()) | ||||
|           ->setName(pht('Call'))); | ||||
|  | ||||
|     return $this->buildApplicationPage( | ||||
|       array( | ||||
|         $param_panel, | ||||
|         $result_panel, | ||||
|         $crumbs, | ||||
|         $param_head, | ||||
|         $param_table, | ||||
|         $result_head, | ||||
|         $result_table, | ||||
|       ), | ||||
|       array( | ||||
|         'title' => 'Method Call Result', | ||||
|         'device' => true, | ||||
|         'dust' => true, | ||||
|       )); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -15,18 +15,19 @@ final class PhabricatorConduitConsoleController | ||||
|   public function processRequest() { | ||||
|  | ||||
|     $request = $this->getRequest(); | ||||
|     $viewer = $request->getUser(); | ||||
|  | ||||
|     $methods = $this->getAllMethods(); | ||||
|     if (empty($methods[$this->method])) { | ||||
|     $method = id(new PhabricatorConduitMethodQuery()) | ||||
|       ->setViewer($viewer) | ||||
|       ->withMethods(array($this->method)) | ||||
|       ->executeOne(); | ||||
|  | ||||
|     if (!$method) { | ||||
|       return new Aphront404Response(); | ||||
|     } | ||||
|     $this->setFilter('method/'.$this->method); | ||||
|  | ||||
|     $method_class = $methods[$this->method]; | ||||
|     $method_object = newv($method_class, array()); | ||||
|  | ||||
|     $status = $method_object->getMethodStatus(); | ||||
|     $reason = $method_object->getMethodStatusDescription(); | ||||
|     $status = $method->getMethodStatus(); | ||||
|     $reason = $method->getMethodStatusDescription(); | ||||
|  | ||||
|     $status_view = null; | ||||
|     if ($status != ConduitAPIMethod::METHOD_STATUS_STABLE) { | ||||
| @@ -49,7 +50,7 @@ final class PhabricatorConduitConsoleController | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     $error_types = $method_object->defineErrorTypes(); | ||||
|     $error_types = $method->defineErrorTypes(); | ||||
|     if ($error_types) { | ||||
|       $error_description = array(); | ||||
|       foreach ($error_types as $error => $meaning) { | ||||
| @@ -68,14 +69,15 @@ final class PhabricatorConduitConsoleController | ||||
|       ->setUser($request->getUser()) | ||||
|       ->setAction('/api/'.$this->method) | ||||
|       ->addHiddenInput('allowEmptyParams', 1) | ||||
|       ->setFlexible(true) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormStaticControl()) | ||||
|           ->setLabel('Description') | ||||
|           ->setValue($method_object->getMethodDescription())) | ||||
|           ->setValue($method->getMethodDescription())) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormStaticControl()) | ||||
|           ->setLabel('Returns') | ||||
|           ->setValue($method_object->defineReturnType())) | ||||
|           ->setValue($method->defineReturnType())) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormMarkupControl()) | ||||
|           ->setLabel('Errors') | ||||
| @@ -85,7 +87,7 @@ final class PhabricatorConduitConsoleController | ||||
|         '<strong>JSON</strong>. For instance, to enter a list, type: '. | ||||
|         '<tt>["apple", "banana", "cherry"]</tt>')); | ||||
|  | ||||
|     $params = $method_object->defineParamTypes(); | ||||
|     $params = $method->defineParamTypes(); | ||||
|     foreach ($params as $param => $desc) { | ||||
|       $form->appendChild( | ||||
|         id(new AphrontFormTextControl()) | ||||
| @@ -106,30 +108,25 @@ final class PhabricatorConduitConsoleController | ||||
|             ))) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormSubmitControl()) | ||||
|           ->addCancelButton($this->getApplicationURI()) | ||||
|           ->setValue('Call Method')); | ||||
|  | ||||
|     $panel = new AphrontPanelView(); | ||||
|     $panel->setHeader('Conduit API: '.$this->method); | ||||
|     $panel->appendChild($form); | ||||
|     $panel->setWidth(AphrontPanelView::WIDTH_FULL); | ||||
|     $crumbs = $this->buildApplicationCrumbs(); | ||||
|     $crumbs->addCrumb( | ||||
|       id(new PhabricatorCrumbView()) | ||||
|         ->setName($method->getAPIMethodName())); | ||||
|  | ||||
|     return $this->buildStandardPageResponse( | ||||
|     return $this->buildApplicationPage( | ||||
|       array( | ||||
|         $crumbs, | ||||
|         $status_view, | ||||
|         $panel, | ||||
|         $form, | ||||
|       ), | ||||
|       array( | ||||
|         'title' => 'Conduit Console - '.$this->method, | ||||
|         'title' => $method->getAPIMethodName(), | ||||
|         'device' => true, | ||||
|         'dust' => true, | ||||
|       )); | ||||
|   } | ||||
|  | ||||
|   private function getAllMethods() { | ||||
|     $classes = $this->getAllMethodImplementationClasses(); | ||||
|     $methods = array(); | ||||
|     foreach ($classes as $class) { | ||||
|       $name = ConduitAPIMethod::getAPIMethodNameFromClassName($class); | ||||
|       $methods[$name] = $class; | ||||
|     } | ||||
|     return $methods; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,122 +5,27 @@ | ||||
|  */ | ||||
| abstract class PhabricatorConduitController extends PhabricatorController { | ||||
|  | ||||
|   private $filter; | ||||
|   protected $showSideNav; | ||||
|   protected function buildSideNavView() { | ||||
|     $viewer = $this->getRequest()->getUser(); | ||||
|  | ||||
|   public function buildStandardPageResponse($view, array $data) { | ||||
|     $page = $this->buildStandardPageView(); | ||||
|     $nav = new AphrontSideNavFilterView(); | ||||
|     $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); | ||||
|  | ||||
|     $page->setApplicationName('Conduit'); | ||||
|     $page->setBaseURI('/conduit/'); | ||||
|     $page->setTitle(idx($data, 'title')); | ||||
|     $page->setGlyph("\xE2\x87\xB5"); | ||||
|     id(new PhabricatorConduitSearchEngine()) | ||||
|       ->setViewer($viewer) | ||||
|       ->addNavigationItems($nav->getMenu()); | ||||
|  | ||||
|     if ($this->showSideNav()) { | ||||
|     $nav->addLabel('Logs'); | ||||
|     $nav->addFilter('log', pht('Call Logs')); | ||||
|  | ||||
|       $nav = new AphrontSideNavFilterView(); | ||||
|       $nav->setBaseURI(new PhutilURI('/conduit/')); | ||||
|       $method_filters = $this->getMethodFilters(); | ||||
|       foreach ($method_filters as $group => $methods) { | ||||
|         $nav->addLabel($group); | ||||
|         foreach ($methods as $method) { | ||||
|           $method_name = $method['full_name']; | ||||
|     $nav->selectFilter(null); | ||||
|  | ||||
|           $display_name = $method_name; | ||||
|           switch ($method['status']) { | ||||
|             case ConduitAPIMethod::METHOD_STATUS_DEPRECATED: | ||||
|               $display_name = '('.$display_name.')'; | ||||
|               break; | ||||
|           } | ||||
|  | ||||
|           $nav->addFilter('method/'.$method_name, | ||||
|             $display_name); | ||||
|         } | ||||
|       } | ||||
|       $nav->selectFilter($this->getFilter()); | ||||
|       $nav->appendChild($view); | ||||
|       $body = $nav; | ||||
|     } else { | ||||
|       $body = $view; | ||||
|     } | ||||
|     $page->appendChild($body); | ||||
|  | ||||
|     $response = new AphrontWebpageResponse(); | ||||
|     return $response->setContent($page->render()); | ||||
|     return $nav; | ||||
|   } | ||||
|  | ||||
|   private function getFilter() { | ||||
|     return $this->filter; | ||||
|   protected function buildApplicationMenu() { | ||||
|     return $this->buildSideNavView()->getMenu(); | ||||
|   } | ||||
|  | ||||
|   protected function setFilter($filter) { | ||||
|     $this->filter = $filter; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   private function showSideNav() { | ||||
|     return $this->showSideNav !== false; | ||||
|   } | ||||
|  | ||||
|   protected function setShowSideNav($show_side_nav) { | ||||
|     $this->showSideNav = $show_side_nav; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   protected function getAllMethodImplementationClasses() { | ||||
|     $classes = id(new PhutilSymbolLoader()) | ||||
|       ->setAncestorClass('ConduitAPIMethod') | ||||
|       ->setType('class') | ||||
|       ->setConcreteOnly(true) | ||||
|       ->selectSymbolsWithoutLoading(); | ||||
|  | ||||
|     return array_values(ipull($classes, 'name')); | ||||
|   } | ||||
|  | ||||
|   protected function getMethodFilters() { | ||||
|     $classes = $this->getAllMethodImplementationClasses(); | ||||
|     $method_names = array(); | ||||
|     foreach ($classes as $method_class) { | ||||
|       $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName( | ||||
|         $method_class); | ||||
|       $group_name = head(explode('.', $method_name)); | ||||
|  | ||||
|       $method_object = newv($method_class, array()); | ||||
|  | ||||
|       $application = $method_object->getApplication(); | ||||
|       if ($application && !$application->isInstalled()) { | ||||
|         continue; | ||||
|       } | ||||
|  | ||||
|       $status = $method_object->getMethodStatus(); | ||||
|  | ||||
|       $key = sprintf( | ||||
|         '%02d %s %s', | ||||
|         $this->getOrderForMethodStatus($status), | ||||
|         $group_name, | ||||
|         $method_name); | ||||
|  | ||||
|       $method_names[$key] = array( | ||||
|         'full_name'   => $method_name, | ||||
|         'group_name'  => $group_name, | ||||
|         'status'      => $status, | ||||
|         'description' => $method_object->getMethodDescription(), | ||||
|       ); | ||||
|     } | ||||
|     ksort($method_names); | ||||
|     $method_names = igroup($method_names, 'group_name'); | ||||
|     ksort($method_names); | ||||
|  | ||||
|     return $method_names; | ||||
|   } | ||||
|  | ||||
|   private function getOrderForMethodStatus($status) { | ||||
|     $map = array( | ||||
|       ConduitAPIMethod::METHOD_STATUS_STABLE      => 0, | ||||
|       ConduitAPIMethod::METHOD_STATUS_UNSTABLE    => 1, | ||||
|       ConduitAPIMethod::METHOD_STATUS_DEPRECATED  => 2, | ||||
|     ); | ||||
|     return idx($map, $status, 0); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,78 +4,78 @@ | ||||
|  * @group conduit | ||||
|  */ | ||||
| final class PhabricatorConduitListController | ||||
|   extends PhabricatorConduitController { | ||||
|   extends PhabricatorConduitController | ||||
|   implements PhabricatorApplicationSearchResultsControllerInterface { | ||||
|  | ||||
|   private $queryKey; | ||||
|  | ||||
|   public function willProcessRequest(array $data) { | ||||
|     $this->queryKey = idx($data, 'queryKey'); | ||||
|   } | ||||
|  | ||||
|   public function processRequest() { | ||||
|     $method_groups = $this->getMethodFilters(); | ||||
|     $rows = array(); | ||||
|     foreach ($method_groups as $group => $methods) { | ||||
|       foreach ($methods as $info) { | ||||
|         switch ($info['status']) { | ||||
|           case ConduitAPIMethod::METHOD_STATUS_DEPRECATED: | ||||
|             $status = 'Deprecated'; | ||||
|             break; | ||||
|           case ConduitAPIMethod::METHOD_STATUS_UNSTABLE: | ||||
|             $status = 'Unstable'; | ||||
|             break; | ||||
|           default: | ||||
|             $status = null; | ||||
|             break; | ||||
|         } | ||||
|     $request = $this->getRequest(); | ||||
|     $controller = id(new PhabricatorApplicationSearchController($request)) | ||||
|       ->setQueryKey($this->queryKey) | ||||
|       ->setSearchEngine(new PhabricatorConduitSearchEngine()) | ||||
|       ->setNavigation($this->buildSideNavView()); | ||||
|     return $this->delegateToController($controller); | ||||
|   } | ||||
|  | ||||
|         $rows[] = array( | ||||
|           $group, | ||||
|           phutil_tag( | ||||
|             'a', | ||||
|             array( | ||||
|               'href' => '/conduit/method/'.$info['full_name'], | ||||
|             ), | ||||
|             $info['full_name']), | ||||
|           $info['description'], | ||||
|           $status, | ||||
|         ); | ||||
|         $group = null; | ||||
|   public function renderResultsList(array $methods) { | ||||
|     assert_instances_of($methods, 'ConduitAPIMethod'); | ||||
|  | ||||
|     $viewer = $this->getRequest()->getUser(); | ||||
|  | ||||
|     $out = array(); | ||||
|  | ||||
|     $last = null; | ||||
|     $list = null; | ||||
|     foreach ($methods as $method) { | ||||
|       $app = $method->getApplicationName(); | ||||
|       if ($app !== $last) { | ||||
|         $last = $app; | ||||
|         if ($list) { | ||||
|           $out[] = $list; | ||||
|         } | ||||
|         $list = id(new PhabricatorObjectItemListView()); | ||||
|  | ||||
|         $app_object = $method->getApplication(); | ||||
|         if ($app_object) { | ||||
|           $app_name = $app_object->getName(); | ||||
|         } else { | ||||
|           $app_name = $app; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       $method_name = $method->getAPIMethodName(); | ||||
|  | ||||
|       $item = id(new PhabricatorObjectItemView()) | ||||
|         ->setHeader($method_name) | ||||
|         ->setHref($this->getApplicationURI('method/'.$method_name.'/')) | ||||
|         ->addAttribute($method->getMethodDescription()); | ||||
|  | ||||
|       switch ($method->getMethodStatus()) { | ||||
|         case ConduitAPIMethod::METHOD_STATUS_STABLE: | ||||
|           break; | ||||
|         case ConduitAPIMethod::METHOD_STATUS_UNSTABLE: | ||||
|           $item->addIcon('warning-grey', pht('Unstable')); | ||||
|           $item->setBarColor('yellow'); | ||||
|           break; | ||||
|         case ConduitAPIMethod::METHOD_STATUS_DEPRECATED: | ||||
|           $item->addIcon('warning', pht('Deprecated')); | ||||
|           $item->setBarColor('red'); | ||||
|           break; | ||||
|       } | ||||
|  | ||||
|       $list->addItem($item); | ||||
|     } | ||||
|  | ||||
|     $table = new AphrontTableView($rows); | ||||
|     $table->setHeaders(array( | ||||
|       'Group', | ||||
|       'Name', | ||||
|       'Description', | ||||
|       'Status', | ||||
|     )); | ||||
|     $table->setColumnClasses(array( | ||||
|       'pri', | ||||
|       'pri', | ||||
|       'wide', | ||||
|       null, | ||||
|     )); | ||||
|     if ($list) { | ||||
|       $out[] = $list; | ||||
|     } | ||||
|  | ||||
|     $panel = new AphrontPanelView(); | ||||
|     $panel->setHeader('Conduit Methods'); | ||||
|     $panel->appendChild($table); | ||||
|     $panel->setWidth(AphrontPanelView::WIDTH_FULL); | ||||
|  | ||||
|     $utils = new AphrontPanelView(); | ||||
|     $utils->setHeader('Utilities'); | ||||
|     $utils->appendChild(hsprintf( | ||||
|       '<ul>'. | ||||
|       '<li><a href="/conduit/log/">Log</a> - Conduit Method Calls</li>'. | ||||
|       '<li><a href="/conduit/token/">Token</a> - Certificate Install</li>'. | ||||
|       '</ul>')); | ||||
|     $utils->setWidth(AphrontPanelView::WIDTH_FULL); | ||||
|  | ||||
|     $this->setShowSideNav(false); | ||||
|  | ||||
|     return $this->buildStandardPageResponse( | ||||
|       array( | ||||
|         $panel, | ||||
|         $utils, | ||||
|       ), | ||||
|       array( | ||||
|         'title' => 'Conduit Console', | ||||
|       )); | ||||
|     return $out; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -41,10 +41,16 @@ final class PhabricatorConduitLogController | ||||
|     $panel->appendChild($table); | ||||
|     $panel->appendChild($pager); | ||||
|  | ||||
|     $this->setShowSideNav(false); | ||||
|     $crumbs = $this->buildApplicationCrumbs(); | ||||
|     $crumbs->addCrumb( | ||||
|       id(new PhabricatorCrumbView()) | ||||
|         ->setName(pht('Call Logs'))); | ||||
|  | ||||
|     return $this->buildStandardPageResponse( | ||||
|       $panel, | ||||
|     return $this->buildApplicationPage( | ||||
|       array( | ||||
|         $crumbs, | ||||
|         $panel, | ||||
|       ), | ||||
|       array( | ||||
|         'title' => 'Conduit Logs', | ||||
|       )); | ||||
|   | ||||
| @@ -28,26 +28,40 @@ final class PhabricatorConduitTokenController | ||||
|       ->setToken(Filesystem::readRandomCharacters(40)) | ||||
|       ->save(); | ||||
|  | ||||
|     $panel = new AphrontPanelView(); | ||||
|     $panel->setHeader('Certificate Install Token'); | ||||
|     $panel->setWidth(AphrontPanelView::WIDTH_FORM); | ||||
|     unset($unguarded); | ||||
|  | ||||
|     $panel->appendChild(hsprintf( | ||||
|       '<p class="aphront-form-instructions">Copy and paste this token into '. | ||||
|       'the prompt given to you by "arc install-certificate":</p>'. | ||||
|       '<p style="padding: 0 0 1em 4em;">'. | ||||
|         '<strong>%s</strong>'. | ||||
|       '</p>'. | ||||
|       '<p class="aphront-form-instructions">arc will then complete the '. | ||||
|       'install process for you.</p>', | ||||
|       $token->getToken())); | ||||
|     $pre_instructions = pht( | ||||
|       'Copy and paste this token into the prompt given to you by '. | ||||
|       '`arc install-certificate`'); | ||||
|  | ||||
|     $this->setShowSideNav(false); | ||||
|     $post_instructions = pht( | ||||
|       'After you copy and paste this token, `arc` will complete '. | ||||
|       'the certificate install process for you.'); | ||||
|  | ||||
|     return $this->buildStandardPageResponse( | ||||
|       $panel, | ||||
|     $form = id(new AphrontFormView()) | ||||
|       ->setUser($user) | ||||
|       ->appendRemarkupInstructions($pre_instructions) | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormTextAreaControl()) | ||||
|           ->setLabel(pht('Token')) | ||||
|           ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) | ||||
|           ->setValue($token->getToken())) | ||||
|       ->appendRemarkupInstructions($post_instructions); | ||||
|  | ||||
|     $crumbs = $this->buildApplicationCrumbs(); | ||||
|     $crumbs->addCrumb( | ||||
|       id(new PhabricatorCrumbView()) | ||||
|         ->setName(pht('Install Certificate'))); | ||||
|  | ||||
|     return $this->buildApplicationPage( | ||||
|       array( | ||||
|         'title' => 'Certificate Install Token', | ||||
|         $crumbs, | ||||
|         $form, | ||||
|       ), | ||||
|       array( | ||||
|         'title' => pht('Certificate Install Token'), | ||||
|         'device' => true, | ||||
|         'dust' => true, | ||||
|       )); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,9 @@ | ||||
|  * @task  status  Method Status | ||||
|  * @group conduit | ||||
|  */ | ||||
| abstract class ConduitAPIMethod { | ||||
| abstract class ConduitAPIMethod | ||||
|   extends Phobject | ||||
|   implements PhabricatorPolicyInterface { | ||||
|  | ||||
|   const METHOD_STATUS_STABLE      = 'stable'; | ||||
|   const METHOD_STATUS_UNSTABLE    = 'unstable'; | ||||
| @@ -21,6 +23,14 @@ abstract class ConduitAPIMethod { | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * This is mostly for compatibility with | ||||
|    * @{class:AphrontCursorPagedPolicyAwareQuery}. | ||||
|    */ | ||||
|   public function getID() { | ||||
|     return $this->getAPIMethodName(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get the status for this method (e.g., stable, unstable or deprecated). | ||||
|    * Should return a METHOD_STATUS_* constant. By default, methods are | ||||
| @@ -62,6 +72,29 @@ abstract class ConduitAPIMethod { | ||||
|     return self::getAPIMethodNameFromClassName(get_class($this)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Return a key which sorts methods by application name, then method status, | ||||
|    * then method name. | ||||
|    */ | ||||
|   public function getSortOrder() { | ||||
|     $name = $this->getAPIMethodName(); | ||||
|  | ||||
|     $map = array( | ||||
|       ConduitAPIMethod::METHOD_STATUS_STABLE      => 0, | ||||
|       ConduitAPIMethod::METHOD_STATUS_UNSTABLE    => 1, | ||||
|       ConduitAPIMethod::METHOD_STATUS_DEPRECATED  => 2, | ||||
|     ); | ||||
|     $ord = idx($map, $this->getMethodStatus(), 0); | ||||
|  | ||||
|     list($head, $tail) = explode('.', $name, 2); | ||||
|  | ||||
|     return "{$head}.{$ord}.{$tail}"; | ||||
|   } | ||||
|  | ||||
|   public function getApplicationName() { | ||||
|     return head(explode('.', $this->getAPIMethodName(), 2)); | ||||
|   } | ||||
|  | ||||
|   public static function getClassNameFromAPIMethodName($method_name) { | ||||
|     $method_fragment = str_replace('.', '_', $method_name); | ||||
|     return 'ConduitAPI_'.$method_fragment.'_Method'; | ||||
| @@ -129,4 +162,25 @@ abstract class ConduitAPIMethod { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
| /* -(  PhabricatorPolicyInterface  )----------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getCapabilities() { | ||||
|     return array( | ||||
|       PhabricatorPolicyCapability::CAN_VIEW, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   public function getPolicy($capability) { | ||||
|     return PhabricatorPolicies::POLICY_USER; | ||||
|   } | ||||
|  | ||||
|   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { | ||||
|     // The policy interface on Conduit calls is currently just to let us hook | ||||
|     // into ApplicationSearch. Calls are always visible (even to logged out | ||||
|     // users). | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										124
									
								
								src/applications/conduit/query/PhabricatorConduitMethodQuery.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/applications/conduit/query/PhabricatorConduitMethodQuery.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| <?php | ||||
|  | ||||
| final class PhabricatorConduitMethodQuery | ||||
|   extends PhabricatorCursorPagedPolicyAwareQuery { | ||||
|  | ||||
|   private $isDeprecated; | ||||
|   private $isStable; | ||||
|   private $isUnstable; | ||||
|   private $applicationNames; | ||||
|   private $nameContains; | ||||
|   private $methods; | ||||
|  | ||||
|   public function withMethods(array $methods) { | ||||
|     $this->methods = $methods; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function withNameContains($name_contains) { | ||||
|     $this->nameContains = $name_contains; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function withApplicationNames(array $application_names) { | ||||
|     $this->applicationNames = $application_names; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function withIsStable($is_stable) { | ||||
|     $this->isStable = $is_stable; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function withIsUnstable($is_unstable) { | ||||
|     $this->isUnstable = $is_unstable; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function withIsDeprecated($is_deprecated) { | ||||
|     $this->isDeprecated = $is_deprecated; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function loadPage() { | ||||
|     $methods = $this->getAllMethods(); | ||||
|  | ||||
|     $methods = $this->filterMethods($methods); | ||||
|  | ||||
|     return $methods; | ||||
|   } | ||||
|  | ||||
|   private function getAllMethods() { | ||||
|     static $methods; | ||||
|     if ($methods === null) { | ||||
|       $methods = id(new PhutilSymbolLoader()) | ||||
|         ->setAncestorClass('ConduitAPIMethod') | ||||
|         ->loadObjects(); | ||||
|       $methods = msort($methods, 'getSortOrder'); | ||||
|     } | ||||
|     return $methods; | ||||
|   } | ||||
|  | ||||
|   private function filterMethods(array $methods) { | ||||
|     foreach ($methods as $key => $method) { | ||||
|       $application = $method->getApplication(); | ||||
|       if (!$application) { | ||||
|         continue; | ||||
|       } | ||||
|       if (!$application->isInstalled()) { | ||||
|         unset($methods[$key]); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     $status = array( | ||||
|       ConduitAPIMethod::METHOD_STATUS_STABLE => $this->isStable, | ||||
|       ConduitAPIMethod::METHOD_STATUS_DEPRECATED => $this->isDeprecated, | ||||
|       ConduitAPIMethod::METHOD_STATUS_UNSTABLE => $this->isUnstable, | ||||
|     ); | ||||
|  | ||||
|     // Only apply status filters if any of them are set. | ||||
|     if (array_filter($status)) { | ||||
|       foreach ($methods as $key => $method) { | ||||
|         $keep = idx($status, $method->getMethodStatus()); | ||||
|         if (!$keep) { | ||||
|           unset($methods[$key]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if ($this->applicationNames) { | ||||
|       $map = array_fuse($this->applicationNames); | ||||
|       foreach ($methods as $key => $method) { | ||||
|         $needle = $method->getApplicationName(); | ||||
|         $needle = phutil_utf8_strtolower($needle); | ||||
|         if (empty($map[$needle])) { | ||||
|           unset($methods[$key]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if ($this->nameContains) { | ||||
|       $needle = phutil_utf8_strtolower($this->nameContains); | ||||
|       foreach ($methods as $key => $method) { | ||||
|         $haystack = $method->getAPIMethodName(); | ||||
|         $haystack = phutil_utf8_strtolower($haystack); | ||||
|         if (strpos($haystack, $needle) === false) { | ||||
|           unset($methods[$key]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if ($this->methods) { | ||||
|       $map = array_fuse($this->methods); | ||||
|       foreach ($methods as $key => $method) { | ||||
|         $needle = $method->getAPIMethodName(); | ||||
|         if (empty($map[$needle])) { | ||||
|           unset($methods[$key]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return $methods; | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,137 @@ | ||||
| <?php | ||||
|  | ||||
| final class PhabricatorConduitSearchEngine | ||||
|   extends PhabricatorApplicationSearchEngine { | ||||
|  | ||||
|   public function getPageSize(PhabricatorSavedQuery $saved) { | ||||
|     return INF; | ||||
|   } | ||||
|  | ||||
|   public function buildSavedQueryFromRequest(AphrontRequest $request) { | ||||
|     $saved = new PhabricatorSavedQuery(); | ||||
|  | ||||
|     $saved->setParameter('isStable', $request->getStr('isStable')); | ||||
|     $saved->setParameter('isUnstable', $request->getStr('isUnstable')); | ||||
|     $saved->setParameter('isDeprecated', $request->getStr('isDeprecated')); | ||||
|  | ||||
|     $saved->setParameter( | ||||
|       'applicationNames', | ||||
|       $request->getStrList('applicationNames')); | ||||
|  | ||||
|     $saved->setParameter('nameContains', $request->getStr('nameContains')); | ||||
|  | ||||
|     return $saved; | ||||
|   } | ||||
|  | ||||
|   public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { | ||||
|     $query = id(new PhabricatorConduitMethodQuery()); | ||||
|  | ||||
|     $query->withIsStable($saved->getParameter('isStable')); | ||||
|     $query->withIsUnstable($saved->getParameter('isUnstable')); | ||||
|     $query->withIsDeprecated($saved->getParameter('isDeprecated')); | ||||
|  | ||||
|     $names = $saved->getParameter('applicationNames', array()); | ||||
|     if ($names) { | ||||
|       $query->withApplicationNames($names); | ||||
|     } | ||||
|  | ||||
|     $contains = $saved->getParameter('nameContains'); | ||||
|     if (strlen($contains)) { | ||||
|       $query->withNameContains($contains); | ||||
|     } | ||||
|  | ||||
|     return $query; | ||||
|   } | ||||
|  | ||||
|   public function buildSearchForm( | ||||
|     AphrontFormView $form, | ||||
|     PhabricatorSavedQuery $saved) { | ||||
|  | ||||
|     $form | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormTextControl()) | ||||
|           ->setLabel('Name Contains') | ||||
|           ->setName('nameContains') | ||||
|           ->setValue($saved->getParameter('nameContains'))); | ||||
|  | ||||
|     $names = $saved->getParameter('applicationNames', array()); | ||||
|     $form | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormTextControl()) | ||||
|           ->setLabel('Applications') | ||||
|           ->setName('applicationNames') | ||||
|           ->setValue(implode(', ', $names)) | ||||
|           ->setCaption( | ||||
|             pht('Example: %s', hsprintf('<tt>differential, paste</tt>')))); | ||||
|  | ||||
|     $is_stable = $saved->getParameter('isStable'); | ||||
|     $is_unstable = $saved->getParameter('isUnstable'); | ||||
|     $is_deprecated = $saved->getParameter('isDeprecated'); | ||||
|     $form | ||||
|       ->appendChild( | ||||
|         id(new AphrontFormCheckboxControl()) | ||||
|           ->setLabel('Stability') | ||||
|           ->addCheckbox( | ||||
|             'isStable', | ||||
|             1, | ||||
|             hsprintf( | ||||
|               '<strong>%s</strong>: %s', | ||||
|               pht('Stable Methods'), | ||||
|               pht('Show established API methods with stable interfaces.')), | ||||
|             $is_stable) | ||||
|           ->addCheckbox( | ||||
|             'isUnstable', | ||||
|             1, | ||||
|             hsprintf( | ||||
|               '<strong>%s</strong>: %s', | ||||
|               pht('Unstable Methods'), | ||||
|               pht('Show new methods which are subject to change.')), | ||||
|             $is_unstable) | ||||
|           ->addCheckbox( | ||||
|             'isDeprecated', | ||||
|             1, | ||||
|             hsprintf( | ||||
|               '<strong>%s</strong>: %s', | ||||
|               pht('Deprecated Methods'), | ||||
|               pht( | ||||
|                 'Show old methods which will be deleted in a future '. | ||||
|                 'version of Phabricator.')), | ||||
|             $is_deprecated)); | ||||
|  | ||||
|  | ||||
|   } | ||||
|  | ||||
|   protected function getURI($path) { | ||||
|     return '/conduit/'.$path; | ||||
|   } | ||||
|  | ||||
|   public function getBuiltinQueryNames() { | ||||
|     $names = array( | ||||
|       'modern' => pht('Modern Methods'), | ||||
|       'all'    => pht('All Methods'), | ||||
|     ); | ||||
|  | ||||
|     return $names; | ||||
|   } | ||||
|  | ||||
|   public function buildSavedQueryFromBuiltin($query_key) { | ||||
|  | ||||
|     $query = $this->newSavedQuery(); | ||||
|     $query->setQueryKey($query_key); | ||||
|  | ||||
|     switch ($query_key) { | ||||
|       case 'modern': | ||||
|         return $query | ||||
|           ->setParameter('isStable', true) | ||||
|           ->setParameter('isUnstable', true); | ||||
|       case 'all': | ||||
|         return $query | ||||
|           ->setParameter('isStable', true) | ||||
|           ->setParameter('isUnstable', true) | ||||
|           ->setParameter('isDeprecated', true); | ||||
|     } | ||||
|  | ||||
|     return parent::buildSavedQueryFromBuiltin($query_key); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -173,16 +173,17 @@ final class PhabricatorApplicationSearchController | ||||
|  | ||||
|       $pager = new AphrontCursorPagerView(); | ||||
|       $pager->readFromRequest($request); | ||||
|       $pager->setPageSize($engine->getPageSize($saved_query)); | ||||
|       $objects = $query->setViewer($request->getUser()) | ||||
|         ->executeWithCursorPager($pager); | ||||
|  | ||||
|       $list = $parent->renderResultsList($objects); | ||||
|       $list->setNoDataString(pht("No results found for this query.")); | ||||
|  | ||||
|       $nav->appendChild($list); | ||||
|  | ||||
|       // TODO: This is a bit hacky. | ||||
|       if ($list instanceof PhabricatorObjectItemListView) { | ||||
|         $list->setNoDataString(pht("No results found for this query.")); | ||||
|         $list->setPager($pager); | ||||
|       } else { | ||||
|         $nav->appendChild($pager); | ||||
|   | ||||
| @@ -305,4 +305,14 @@ abstract class PhabricatorApplicationSearchEngine { | ||||
|           ->setLabel($end_name) | ||||
|           ->setValue($end_str)); | ||||
|   } | ||||
|  | ||||
|  | ||||
| /* -(  Pagination  )--------------------------------------------------------- */ | ||||
|  | ||||
|  | ||||
|   public function getPageSize(PhabricatorSavedQuery $saved) { | ||||
|     return $saved->getParameter('limit', 100); | ||||
|   } | ||||
|  | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley