public function test_CheckIfMethodComment_DoesNotContainHideAnnotation()
 {
     $annotation = '@not found here';
     EventDispatcher::getInstance()->addObserver('API.DocumentationGenerator.@hello', function (&$hide) {
         $hide = true;
     });
     $this->assertEquals(Proxy::getInstance()->shouldHideAPIMethod($annotation), false);
 }
Example #2
0
 public function listAllAPI()
 {
     $view = new View("@API/listAllAPI");
     $this->setGeneralVariablesView($view);
     $ApiDocumentation = new DocumentationGenerator();
     $view->countLoadedAPI = Proxy::getInstance()->getCountRegisteredClasses();
     $view->list_api_methods_with_links = $ApiDocumentation->getAllInterfaceString();
     return $view->render();
 }
Example #3
0
 /**
  * Renders a report depending on the configured ViewDataTable see {@link configureView()} and
  * {@link getDefaultTypeViewDataTable()}. If you want to customize the render process or just render any custom view
  * you can overwrite this method.
  *
  * @return string
  * @throws \Exception In case the given API action does not exist yet.
  * @api
  */
 public function render()
 {
     $apiProxy = Proxy::getInstance();
     if (!$apiProxy->isExistingApiAction($this->module, $this->action)) {
         throw new Exception("Invalid action name '{$this->action}' for '{$this->module}' plugin.");
     }
     $apiAction = $apiProxy->buildApiActionName($this->module, $this->action);
     $view = ViewDataTableFactory::build(null, $apiAction, $this->module . '.' . $this->action);
     $rendered = $view->render();
     return $rendered;
 }
Example #4
0
 private function getAllApiMethods()
 {
     $result = array();
     foreach (Proxy::getInstance()->getMetadata() as $class => $info) {
         $moduleName = Proxy::getInstance()->getModuleNameFromClassName($class);
         foreach ($info as $methodName => $infoMethod) {
             if ($this->shouldSkipApiMethod($moduleName, $methodName)) {
                 continue;
             }
             $result[] = array($class, $moduleName, $methodName);
         }
     }
     return $result;
 }
Example #5
0
 /**
  * Convenience method that creates and renders a ViewDataTable for a API method.
  *
  * @param string|\Piwik\Plugin\Report $apiAction The name of the API action (eg, `'getResolution'`) or
  *                                      an instance of an report.
  * @param bool $controllerAction The name of the Controller action name  that is rendering the report. Defaults
  *                               to the `$apiAction`.
  * @param bool $fetch If `true`, the rendered string is returned, if `false` it is `echo`'d.
  * @throws \Exception if `$pluginName` is not an existing plugin or if `$apiAction` is not an
  *                    existing method of the plugin's API.
  * @return string|void See `$fetch`.
  * @api
  */
 protected function renderReport($apiAction, $controllerAction = false)
 {
     if (empty($controllerAction) && is_string($apiAction)) {
         $report = Report::factory($this->pluginName, $apiAction);
         if (!empty($report)) {
             $apiAction = $report;
         }
     }
     if ($apiAction instanceof Report) {
         $this->checkSitePermission();
         $apiAction->checkIsEnabled();
         return $apiAction->render();
     }
     $pluginName = $this->pluginName;
     /** @var Proxy $apiProxy */
     $apiProxy = Proxy::getInstance();
     if (!$apiProxy->isExistingApiAction($pluginName, $apiAction)) {
         throw new \Exception("Invalid action name '{$apiAction}' for '{$pluginName}' plugin.");
     }
     $apiAction = $apiProxy->buildApiActionName($pluginName, $apiAction);
     if ($controllerAction !== false) {
         $controllerAction = $pluginName . '.' . $controllerAction;
     }
     $view = ViewDataTableFactory::build(null, $apiAction, $controllerAction);
     $rendered = $view->render();
     return $rendered;
 }
Example #6
0
 /**
  * @internal
  */
 protected function loadDataTableFromAPI()
 {
     if (!is_null($this->dataTable)) {
         // data table is already there
         // this happens when setDataTable has been used
         return $this->dataTable;
     }
     // we build the request (URL) to call the API
     $request = $this->buildApiRequestArray();
     $module = $this->requestConfig->getApiModuleToRequest();
     $method = $this->requestConfig->getApiMethodToRequest();
     PluginManager::getInstance()->checkIsPluginActivated($module);
     $class = ApiRequest::getClassNameAPI($module);
     $dataTable = Proxy::getInstance()->call($class, $method, $request);
     $response = new ResponseBuilder($format = 'original', $request);
     $response->disableSendHeader();
     $response->disableDataTablePostProcessor();
     $this->dataTable = $response->getResponse($dataTable, $module, $method);
 }
Example #7
0
 /**
  * Dispatches the API request to the appropriate API method and returns the result
  * after post-processing.
  *
  * Post-processing includes:
  *
  * - flattening if **flat** is 0
  * - running generic filters unless **disable_generic_filters** is set to 1
  * - URL decoding label column values
  * - running queued filters unless **disable_queued_filters** is set to 1
  * - removing columns based on the values of the **hideColumns** and **showColumns** query parameters
  * - filtering rows if the **label** query parameter is set
  * - converting the result to the appropriate format (ie, XML, JSON, etc.)
  *
  * If `'original'` is supplied for the output format, the result is returned as a PHP
  * object.
  *
  * @throws PluginDeactivatedException if the module plugin is not activated.
  * @throws Exception if the requested API method cannot be called, if required parameters for the
  *                   API method are missing or if the API method throws an exception and the **format**
  *                   query parameter is **original**.
  * @return DataTable|Map|string The data resulting from the API call.
  */
 public function process()
 {
     // read the format requested for the output data
     $outputFormat = strtolower(Common::getRequestVar('format', 'xml', 'string', $this->request));
     // create the response
     $response = new ResponseBuilder($outputFormat, $this->request);
     $corsHandler = new CORSHandler();
     $corsHandler->handle();
     try {
         // read parameters
         $moduleMethod = Common::getRequestVar('method', null, 'string', $this->request);
         list($module, $method) = $this->extractModuleAndMethod($moduleMethod);
         $module = $this->renameModule($module);
         if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated($module)) {
             throw new PluginDeactivatedException($module);
         }
         $apiClassName = $this->getClassNameAPI($module);
         self::reloadAuthUsingTokenAuth($this->request);
         // call the method
         $returnedValue = Proxy::getInstance()->call($apiClassName, $method, $this->request);
         $toReturn = $response->getResponse($returnedValue, $module, $method);
     } catch (Exception $e) {
         Log::debug($e);
         $toReturn = $response->getResponseException($e);
     }
     return $toReturn;
 }
Example #8
0
 /**
  * Renders a report depending on the configured ViewDataTable see {@link configureView()} and
  * {@link getDefaultTypeViewDataTable()}. If you want to customize the render process or just render any custom view
  * you can overwrite this method.
  *
  * @return string
  * @throws \Exception In case the given API action does not exist yet.
  * @api
  */
 public function render()
 {
     $viewDataTable = Common::getRequestVar('viewDataTable', false, 'string');
     $fixed = Common::getRequestVar('forceView', 0, 'int');
     $module = $this->getModule();
     $action = $this->getAction();
     $apiProxy = Proxy::getInstance();
     if (!$apiProxy->isExistingApiAction($module, $action)) {
         throw new Exception("Invalid action name '{$module}' for '{$action}' plugin.");
     }
     $apiAction = $apiProxy->buildApiActionName($module, $action);
     $view = ViewDataTableFactory::build($viewDataTable, $apiAction, $module . '.' . $action, $fixed);
     return $view->render();
 }
 public function tearDown()
 {
     Proxy::getInstance()->setHideIgnoredFunctions(true);
 }
Example #10
0
 /**
  * Get a combined report of the *.get API methods.
  */
 public function get($idSite, $period, $date, $segment = false, $columns = false)
 {
     Piwik::checkUserHasViewAccess($idSite);
     $columns = Piwik::getArrayFromApiParameter($columns);
     // build columns map for faster checks later on
     $columnsMap = array();
     foreach ($columns as $column) {
         $columnsMap[$column] = true;
     }
     // find out which columns belong to which plugin
     $columnsByPlugin = array();
     $meta = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite, $period, $date);
     foreach ($meta as $reportMeta) {
         // scan all *.get reports
         if ($reportMeta['action'] == 'get' && !isset($reportMeta['parameters']) && $reportMeta['module'] != 'API' && !empty($reportMeta['metrics'])) {
             $plugin = $reportMeta['module'];
             $allMetrics = array_merge($reportMeta['metrics'], @$reportMeta['processedMetrics'] ?: array());
             foreach ($allMetrics as $column => $columnTranslation) {
                 // a metric from this report has been requested
                 if (isset($columnsMap[$column]) || empty($columnsMap)) {
                     $columnsByPlugin[$plugin][] = $column;
                 }
             }
         }
     }
     krsort($columnsByPlugin);
     $mergedDataTable = false;
     $params = compact('idSite', 'period', 'date', 'segment', 'idGoal');
     foreach ($columnsByPlugin as $plugin => $columns) {
         // load the data
         $className = Request::getClassNameAPI($plugin);
         $params['columns'] = implode(',', $columns);
         $dataTable = Proxy::getInstance()->call($className, 'get', $params);
         $dataTable->filter(function (DataTable $table) {
             $table->clearQueuedFilters();
         });
         // merge reports
         if ($mergedDataTable === false) {
             $mergedDataTable = $dataTable;
         } else {
             $merger = new MergeDataTables();
             $merger->mergeDataTables($mergedDataTable, $dataTable);
         }
     }
     if (!empty($columnsMap) && !empty($mergedDataTable)) {
         $mergedDataTable->queueFilter('ColumnDelete', array(false, array_keys($columnsMap)));
     }
     return $mergedDataTable;
 }
Example #11
0
 /**
  * Get a combined report of the *.get API methods.
  */
 public function get($idSite, $period, $date, $segment = false, $columns = false)
 {
     $columns = Piwik::getArrayFromApiParameter($columns);
     // build columns map for faster checks later on
     $columnsMap = array();
     foreach ($columns as $column) {
         $columnsMap[$column] = true;
     }
     // find out which columns belong to which plugin
     $columnsByPlugin = array();
     $meta = \Piwik\Plugins\API\API::getInstance()->getReportMetadata($idSite, $period, $date);
     foreach ($meta as $reportMeta) {
         // scan all *.get reports
         if ($reportMeta['action'] == 'get' && !isset($reportMeta['parameters']) && $reportMeta['module'] != 'API' && !empty($reportMeta['metrics'])) {
             $plugin = $reportMeta['module'];
             foreach ($reportMeta['metrics'] as $column => $columnTranslation) {
                 // a metric from this report has been requested
                 if (isset($columnsMap[$column]) || empty($columnsMap)) {
                     $columnsByPlugin[$plugin][] = $column;
                 }
             }
         }
     }
     krsort($columnsByPlugin);
     $mergedDataTable = false;
     $params = compact('idSite', 'period', 'date', 'segment', 'idGoal');
     foreach ($columnsByPlugin as $plugin => $columns) {
         // load the data
         $className = Request::getClassNameAPI($plugin);
         $params['columns'] = implode(',', $columns);
         $dataTable = Proxy::getInstance()->call($className, 'get', $params);
         // make sure the table has all columns
         $array = $dataTable instanceof DataTable\Map ? $dataTable->getDataTables() : array($dataTable);
         foreach ($array as $table) {
             // we don't support idSites=all&date=DATE1,DATE2
             if ($table instanceof DataTable) {
                 $firstRow = $table->getFirstRow();
                 if (!$firstRow) {
                     $firstRow = new Row();
                     $table->addRow($firstRow);
                 }
                 foreach ($columns as $column) {
                     if ($firstRow->getColumn($column) === false) {
                         $firstRow->setColumn($column, 0);
                     }
                 }
             }
         }
         // merge reports
         if ($mergedDataTable === false) {
             $mergedDataTable = $dataTable;
         } else {
             $this->mergeDataTables($mergedDataTable, $dataTable);
         }
     }
     return $mergedDataTable;
 }
 public function tearDown()
 {
     parent::tearDown();
     // reset that value after the test
     Proxy::getInstance()->setHideIgnoredFunctions(true);
 }
Example #13
0
 /**
  * Dispatches the API request to the appropriate API method and returns the result
  * after post-processing.
  *
  * Post-processing includes:
  *
  * - flattening if **flat** is 0
  * - running generic filters unless **disable_generic_filters** is set to 1
  * - URL decoding label column values
  * - running queued filters unless **disable_queued_filters** is set to 1
  * - removing columns based on the values of the **hideColumns** and **showColumns** query parameters
  * - filtering rows if the **label** query parameter is set
  * - converting the result to the appropriate format (ie, XML, JSON, etc.)
  *
  * If `'original'` is supplied for the output format, the result is returned as a PHP
  * object.
  *
  * @throws PluginDeactivatedException if the module plugin is not activated.
  * @throws Exception if the requested API method cannot be called, if required parameters for the
  *                   API method are missing or if the API method throws an exception and the **format**
  *                   query parameter is **original**.
  * @return DataTable|Map|string The data resulting from the API call.
  */
 public function process()
 {
     // read the format requested for the output data
     $outputFormat = strtolower(Common::getRequestVar('format', 'xml', 'string', $this->request));
     // create the response
     $response = new ResponseBuilder($outputFormat, $this->request);
     $corsHandler = new CORSHandler();
     $corsHandler->handle();
     $tokenAuth = Common::getRequestVar('token_auth', '', 'string', $this->request);
     $shouldReloadAuth = false;
     try {
         // read parameters
         $moduleMethod = Common::getRequestVar('method', null, 'string', $this->request);
         list($module, $method) = $this->extractModuleAndMethod($moduleMethod);
         list($module, $method) = self::getRenamedModuleAndAction($module, $method);
         PluginManager::getInstance()->checkIsPluginActivated($module);
         $apiClassName = self::getClassNameAPI($module);
         if ($shouldReloadAuth = self::shouldReloadAuthUsingTokenAuth($this->request)) {
             $access = Access::getInstance();
             $tokenAuthToRestore = $access->getTokenAuth();
             $hadSuperUserAccess = $access->hasSuperUserAccess();
             self::forceReloadAuthUsingTokenAuth($tokenAuth);
         }
         // call the method
         $returnedValue = Proxy::getInstance()->call($apiClassName, $method, $this->request);
         $toReturn = $response->getResponse($returnedValue, $module, $method);
     } catch (Exception $e) {
         Log::debug($e);
         $toReturn = $response->getResponseException($e);
     }
     if ($shouldReloadAuth) {
         $this->restoreAuthUsingTokenAuth($tokenAuthToRestore, $hadSuperUserAccess);
     }
     return $toReturn;
 }
Example #14
0
 /**
  * Given a list of default parameters to set, returns the URLs of APIs to call
  * If any API was specified in $this->apiNotToCall we ensure only these are tested.
  * If any API is set as excluded (see list below) then it will be ignored.
  *
  * @param array $parametersToSet Parameters to set in api call
  * @param array $formats         Array of 'format' to fetch from API
  * @param array $periods         Array of 'period' to query API
  * @param bool  $supertableApi
  * @param bool  $setDateLastN    If set to true, the 'date' parameter will be rewritten to query instead a range of dates, rather than one period only.
  * @param bool|string $language        2 letter language code, defaults to default piwik language
  * @param bool|string $fileExtension
  *
  * @throws Exception
  *
  * @return array of API URLs query strings
  */
 protected function generateUrlsApi($parametersToSet, $formats, $periods, $supertableApi = false, $setDateLastN = false, $language = false, $fileExtension = false)
 {
     // Get the URLs to query against the API for all functions starting with get*
     $skipped = $requestUrls = array();
     $apiMetadata = new DocumentationGenerator();
     foreach (Proxy::getInstance()->getMetadata() as $class => $info) {
         $moduleName = Proxy::getInstance()->getModuleNameFromClassName($class);
         foreach ($info as $methodName => $infoMethod) {
             $apiId = $moduleName . '.' . $methodName;
             // If Api to test were set, we only test these
             if (!empty($this->apiToCall) && in_array($moduleName, $this->apiToCall) === false && in_array($apiId, $this->apiToCall) === false) {
                 $skipped[] = $apiId;
                 continue;
             } elseif (strpos($methodName, 'get') !== 0 && $methodName != 'generateReport' || in_array($moduleName, $this->apiNotToCall) === true || in_array($apiId, $this->apiNotToCall) === true || $methodName == 'getLogoUrl' || $methodName == 'getSVGLogoUrl' || $methodName == 'hasSVGLogo' || $methodName == 'getHeaderLogoUrl') {
                 // Excluded modules from test
                 $skipped[] = $apiId;
                 continue;
             }
             foreach ($periods as $period) {
                 $parametersToSet['period'] = $period;
                 // If date must be a date range, we process this date range by adding 6 periods to it
                 if ($setDateLastN) {
                     if (!isset($parametersToSet['dateRewriteBackup'])) {
                         $parametersToSet['dateRewriteBackup'] = $parametersToSet['date'];
                     }
                     $lastCount = (int) $setDateLastN;
                     if ($setDateLastN === true) {
                         $lastCount = 6;
                     }
                     $firstDate = $parametersToSet['dateRewriteBackup'];
                     $secondDate = date('Y-m-d', strtotime("+{$lastCount} " . $period . "s", strtotime($firstDate)));
                     $parametersToSet['date'] = $firstDate . ',' . $secondDate;
                 }
                 // Set response language
                 if ($language !== false) {
                     $parametersToSet['language'] = $language;
                 }
                 // set idSubtable if subtable API is set
                 if ($supertableApi !== false) {
                     $request = new Request(array('module' => 'API', 'method' => $supertableApi, 'idSite' => $parametersToSet['idSite'], 'period' => $parametersToSet['period'], 'date' => $parametersToSet['date'], 'format' => 'php', 'serialize' => 0));
                     // find first row w/ subtable
                     $content = $request->process();
                     $this->checkRequestResponse($content);
                     foreach ($content as $row) {
                         if (isset($row['idsubdatatable'])) {
                             $parametersToSet['idSubtable'] = $row['idsubdatatable'];
                             break;
                         }
                     }
                     // if no subtable found, throw
                     if (!isset($parametersToSet['idSubtable'])) {
                         throw new Exception("Cannot find subtable to load for {$apiId} in {$supertableApi}.");
                     }
                 }
                 // Generate for each specified format
                 foreach ($formats as $format) {
                     $parametersToSet['format'] = $format;
                     $parametersToSet['hideIdSubDatable'] = 1;
                     $parametersToSet['serialize'] = 1;
                     $exampleUrl = $apiMetadata->getExampleUrl($class, $methodName, $parametersToSet);
                     if ($exampleUrl === false) {
                         $skipped[] = $apiId;
                         continue;
                     }
                     // Remove the first ? in the query string
                     $exampleUrl = substr($exampleUrl, 1);
                     $apiRequestId = $apiId;
                     if (strpos($exampleUrl, 'period=') !== false) {
                         $apiRequestId .= '_' . $period;
                     }
                     $apiRequestId .= '.' . $format;
                     if ($fileExtension) {
                         $apiRequestId .= '.' . $fileExtension;
                     }
                     $requestUrls[$apiRequestId] = $exampleUrl;
                 }
             }
         }
     }
     return $requestUrls;
 }
Example #15
0
 /**
  * Convenience method that creates and renders a ViewDataTable for a API method.
  *
  * @param string $apiAction The name of the API action (eg, `'getResolution'`).
  * @param bool $controllerAction The name of the Controller action name  that is rendering the report. Defaults
  *                               to the `$apiAction`.
  * @param bool $fetch If `true`, the rendered string is returned, if `false` it is `echo`'d.
  * @throws \Exception if `$pluginName` is not an existing plugin or if `$apiAction` is not an
  *                    existing method of the plugin's API.
  * @return string|void See `$fetch`.
  * @api
  */
 protected function renderReport($apiAction, $controllerAction = false)
 {
     $pluginName = $this->pluginName;
     /** @var Proxy $apiProxy */
     $apiProxy = Proxy::getInstance();
     if (!$apiProxy->isExistingApiAction($pluginName, $apiAction)) {
         throw new \Exception("Invalid action name '{$apiAction}' for '{$pluginName}' plugin.");
     }
     $apiAction = $apiProxy->buildApiActionName($pluginName, $apiAction);
     if ($controllerAction !== false) {
         $controllerAction = $pluginName . '.' . $controllerAction;
     }
     $view = ViewDataTableFactory::build(null, $apiAction, $controllerAction);
     $rendered = $view->render();
     return $rendered;
 }
 protected function callApiAndReturnDataTable($apiModule, $method, $request)
 {
     $class = Request::getClassNameAPI($apiModule);
     $request = $this->manipulateSubtableRequest($request);
     $request['serialize'] = 0;
     $request['expanded'] = 0;
     // don't want to run recursive filters on the subtables as they are loaded,
     // otherwise the result will be empty in places (or everywhere). instead we
     // run it on the flattened table.
     unset($request['filter_pattern_recursive']);
     $dataTable = Proxy::getInstance()->call($class, $method, $request);
     $response = new ResponseBuilder($format = 'original', $request);
     $response->disableSendHeader();
     $dataTable = $response->getResponse($dataTable);
     if (Common::getRequestVar('disable_queued_filters', 0, 'int', $request) == 0) {
         if (method_exists($dataTable, 'applyQueuedFilters')) {
             $dataTable->applyQueuedFilters();
         }
     }
     return $dataTable;
 }
 /**
  * Returns the methods $class.$name parameters (and default value if provided) as a string.
  *
  * @param string $class The class name
  * @param string $name The method name
  * @return string  For example "(idSite, period, date = 'today')"
  */
 public function getParametersString($class, $name)
 {
     $aParameters = Proxy::getInstance()->getParametersList($class, $name);
     $asParameters = array();
     foreach ($aParameters as $nameVariable => $defaultValue) {
         // Do not show API parameters starting with _
         // They are supposed to be used only in internal API calls
         if (strpos($nameVariable, '_') === 0) {
             continue;
         }
         $str = $nameVariable;
         if (!$defaultValue instanceof NoDefaultValue) {
             if (is_array($defaultValue)) {
                 $str .= " = 'Array'";
             } else {
                 $str .= " = '{$defaultValue}'";
             }
         }
         $asParameters[] = $str;
     }
     $sParameters = implode(", ", $asParameters);
     return "({$sParameters})";
 }