diff --git a/js/app/controllers/EpnTapModule.js b/js/app/controllers/EpnTapModule.js index e6f98cd..1f2479e 100644 --- a/js/app/controllers/EpnTapModule.js +++ b/js/app/controllers/EpnTapModule.js @@ -130,7 +130,7 @@ Ext.define('amdaDesktop.EpnTapModule', { loadMask.show(); this.servicesStore.each(function(record) { - // TODO: use store.load() method instead. + // TODO: use store.load() method instead and add 'success' and 'enable' columns in the store Ext.Ajax.request({ url: 'php/epntap.php', method: 'GET', @@ -146,8 +146,18 @@ Ext.define('amdaDesktop.EpnTapModule', { 'timeMax': timeMax }, // timeout: 3000, - success: this.updateNbResults, - failure: this.updateNbResultsFail, + success: function(response) { + var record = this.servicesStore.getById(response.request.options.params['serviceId']); + var responseObj = Ext.decode(response.responseText); + if(responseObj['success']) { + this.updateNbResults(responseObj, record); + } else { + this.updateNbResultsFail(response, responseObj['msg']); + } + }, + failure: function(response) { + this.updateNbResultsFail(response, response.statusText); + }, scope: this }); }, this); @@ -156,25 +166,21 @@ Ext.define('amdaDesktop.EpnTapModule', { /** Update the nb_result field of the services store (see `EpnTapUI.servicesStore`), according to the field values in `serviceFilterPanel`. */ - updateNbResults: function(response) { - if(response.status !== 200 || isNaN(response.responseText)) { - this.updateNbResultsFail(response); - } else { - var record = this.servicesStore.getById(response.request.options.params['serviceId']); - var nbRes = Number(response.responseText); - record.set('nb_results', response.responseText); - record.set('error', ''); - record.set('info', 'The service returned ' + (nbRes == 0 ? 'any' : nbRes) + ' result' + (nbRes > 1 ? 's' : '') + ' for the given query.'); - this.servicesStore.sort(); - } + updateNbResults: function(responseObj, record) { + record.set('nb_results', responseObj['data']); + record.set('info', responseObj['msg']); + record.set('error', ''); + this.servicesStore.sort(); loadMask.hide(); }, - updateNbResultsFail: function(response) { - var record = this.servicesStore.getById(response.request.options.params['serviceId']); - var reason = response.status === 200 ? response.responseText : response.statusText; - record.set('error', reason); + updateNbResultsFail: function(response, reason) { + var serviceId = response.request.options.params['serviceId']; + var record = this.servicesStore.getById(serviceId); + console.log('Can not get nb results for service ' + serviceId + ': ' + reason, response); record.set('info', ''); + record.set('error', reason); + this.servicesStore.sort(); loadMask.hide(); }, @@ -203,9 +209,11 @@ Ext.define('amdaDesktop.EpnTapModule', { // Ext.Ajax.abortAll(); this.selectedService = record; var nbRes = this.selectedService.get('nb_results'); - if(nbRes > 0 && !isNaN(nbRes)) { + + if(nbRes > 0 && !isNaN(nbRes)) { // TODO replace !isNaN(nbRes) by this.selectedService.get('success') this.granulesStore.load({ params: this.getGranuleParams(), + // callback: function (records, operation) { console.log(Ext.decode(operation.response.responseText)); }, start: 0, limit: this.granulesStore.pageSize, scope: this diff --git a/js/app/views/EpnTapUI.js b/js/app/views/EpnTapUI.js index 016ea3e..47a7111 100644 --- a/js/app/views/EpnTapUI.js +++ b/js/app/views/EpnTapUI.js @@ -48,6 +48,8 @@ Ext.create('Ext.data.Store', { ] }); +// TODO: Create a generic epntap stop from which all other stores inherits. + /** `targetNamesStore`: An ExtJS Store containing the list of the different target names defined on all granules, on all available EPN-TAP services (defined in `generic_data/EpnTapData/metadata.json`, updated periodically with a cron @@ -65,7 +67,12 @@ Ext.create('Ext.data.Store', { proxy: { type: 'ajax', url: 'php/epntap.php', - extraParams : { action: 'resolver' } + extraParams: { action: 'resolver' } + // listeners: { + // exception: function(proxy, response, operation) { + // console.log('Error ', response); //TODO: Use ExtJs alert instead + // } + // } } }); @@ -140,7 +147,7 @@ selected. */ Ext.create('Ext.data.Store', { id: 'granulesStore', - model: 'granulesModel', + model: 'granulesModel', // Created dynamically autoload: false, pageSize: 25, proxy: { diff --git a/php/epntap.php b/php/epntap.php index 2fe0892..6e84db2 100644 --- a/php/epntap.php +++ b/php/epntap.php @@ -1,43 +1,76 @@ <?php include(realpath(dirname(__FILE__) . "/config.php")); -// include(CLASSPATH . "EpnTapMgr.php"); include(CLASSPATH . "VOTableMgr.php"); $action = preg_replace("/[^a-zA-Z]+/", "", filter_var($_GET['action'], FILTER_SANITIZE_STRING)); switch ($action) { case 'resolver': - $response = json_encode(resolver()); + $response = resolver(); break; case 'getServices': - $response = json_encode(getServices()); + $response = getServices(); break; case 'getNbResults': $response = getNbResults(); break; case 'getGranules': - $response = json_encode(getGranules()); + $response = getGranules(); break; default: - $response = 'unknown action'; + $response = ['success' => false, 'msg' => 'Unknown action: ' . $action]; break; } -// error_log('epntap response: ' . $response); -echo $response; +echo json_encode($response); function resolver() { $input = filter_var($_GET['input'], FILTER_SANITIZE_URL); $resolver_url = "http://voparis-registry.obspm.fr/ssodnet/1/autocomplete?q=%22$input%22"; - $result = json_decode(file_get_contents($resolver_url), true); - $targets = array(); - foreach($result['hits'] as $e) { - $aliases = '<li>' . join('</li><li>', $e['aliases']) . '</li>'; - $target = array('name' => $e['name'], 'type' => $e['type'], 'parent' => $e['parent'], 'aliases' => $aliases); - array_push($targets, $target); + $response = ['success' => true, 'metaData' => ['root' => 'data', 'messageProperty' => 'msg']]; + try { + $content = file_get_contents($resolver_url); + } catch (Exception $e) { + error_log('Resolver access error: ' . $e); + $response['success'] = false; + $response['msg'] = "Resolver unreachable on $resolver_url."; } - return $targets; + try { + $result = json_decode($content, true); + $targets = array(); + foreach($result['hits'] as $e) { + $aliases = '<li>' . join('</li><li>', $e['aliases']) . '</li>'; + $target = array('name' => $e['name'], 'type' => $e['type'], 'parent' => $e['parent'], 'aliases' => $aliases); + array_push($targets, $target); + } + $response['data'] = $targets; + } catch (Exception $e) { + error_log('Resolver type error: ' . $e); + $response['success'] = false; + $response['msg'] = 'The resolver returned a bad result.'; + } + return $response; +} + +function request($access_url, $query) { + $votMgr = new VOTableMgr; + $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; + $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode(preg_replace('/\s+/', ' ', $query)); // remove also multiple whitespaces + + $votMgr->load($url); + $data = $votMgr->parseStream(); + $error = $votMgr->getVotableError(); + + $response = ['query' => $query, 'metaData' => ['root' => 'data', 'messageProperty' => 'msg']]; + if($error) { + $response['success'] = false; + $response['msg'] = $error; + } else { + $response['success'] = true; + $response['data'] = $data; + } + return $response; } /* Return the list of available services by querying some usual registries. */ @@ -48,29 +81,33 @@ function getServices() { NATURAL JOIN rr.res_schema NATURAL JOIN rr.res_table NATURAL JOIN rr.interface NATURAL JOIN rr.res_detail NATURAL JOIN rr.capability WHERE standard_id='ivo://ivoa.net/std/tap' AND intf_type='vs:paramhttp' AND detail_xpath='/capability/dataModel/@ivo-id' AND 1=ivo_nocasematch(detail_value, 'ivo://vopdc.obspm/std/EpnCore%') AND table_name LIKE '%.epn_core' ORDER BY short_name, table_name"; - // error_log('getServices query: ' . $query); - - for($i=0; $i<count($registriesURL); $i++) { - $services = request($registriesURL[$i], $query); - if(! array_key_exists("error", $services)) { - for($j=0; $j<count($services); $j++) { - $services[$j]['id'] = generateServiceId($services[$j]); - $services[$j]['nb_results'] = -1; - $services[$j]['info'] = 'Please make a query first.'; - if($services[$j]['id'] == 'cdpp/amda/amdadb') { - array_splice($services, $j, 1); + + $regNumber = 0; + for(; $regNumber<count($registriesURL) ; $regNumber++) { + $response = request($registriesURL[$regNumber], $query); + if($response['success']) { + // Add several other parameters and remove AMDA + for($j=0 ; $j<count($response['data']) ; $j++) { + $response['data'][$j]['id'] = generateServiceId($response['data'][$j]); + $response['data'][$j]['nb_results'] = -1; + $response['data'][$j]['info'] = 'Please make a query.'; + if($response['data'][$j]['id'] == 'cdpp/amda/amdadb') { + array_splice($response['data'], $j, 1); $j-=1; } } - return $services; - } else { - error_log('getServices error: ' . $services['error']); - if($i === count($registriesURL)-1) { - error_log("Can not access any of these registries : " . implode(', ', $registriesURL) . ", check the internet connexion."); - return; + if(isset($lastErrorMesage)) { + $response['msg'] = $lastErrorMesage; } + break; + } else { + $lastErrorMesage = 'Last tried registry (' . $registriesURL[$regNumber] . ') returned this error: ' . $response['msg'] . '.'; } } + if(!$response['success']) { + $response['msg'] = 'Can not access any of these registries: ' . implode(', ', $registriesURL) . ', last error message is ' . $lastErrorMesage; + } + return $response; } function getNbResults() { @@ -82,27 +119,33 @@ function getNbResults() { $timeMax = filter_var($_GET['timeMax'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); $query = "SELECT COUNT(*) AS nb_rows FROM $tableName" . createFilter($targetName, $productTypes, $timeMin, $timeMax); - // error_log('getNbResults query: ' . $query); - $result = request($url, $query); - if(count($result) < 1) { - return 'Too few returned raws.'; - } else if(count($result) > 1) { - return 'Too many returned raws.'; - } else if(!array_key_exists(0, $result)) { - return 'cant find raw item 0'; - } else if(is_null($result[0])) { - return 'The returned raw is null.'; - } else if(!array_key_exists("nb_rows", $result[0])) { - return 'cant find nb_rows.'; - } else if(!is_numeric($result[0]['nb_rows'])) { - return 'The returned value is not a number.'; - } else { - return (int)($result[0]['nb_rows']); + $response = request($url, $query); + if($response['success']) { + $response['success'] = false; + $response['msg'] = 'The service returned a bad value, can not get the number of results.'; + if(count($response['data']) < 1) { + error_log('getNbResults error: Too few returned raws.'); + } else if(count($response['data']) > 1) { + error_log('getNbResults error: Too many returned raws.'); + } else if(!array_key_exists(0, $response['data'])) { + error_log('getNbResults error: cant find raw item 0'); + } else if(is_null($response['data'][0])) { + error_log('getNbResults error: The returned raw is null.'); + } else if(!array_key_exists("nb_rows", $response['data'][0])) { + error_log('getNbResults error: cant find nb_rows.'); + } else if(!is_numeric($response['data'][0]['nb_rows'])) { + error_log('getNbResults error: The returned value is not a number.'); + } else { + $response['success'] = true; + $response['data'] = (int)($response['data'][0]['nb_rows']); + $response['msg'] = 'The service returned ' . ($response['data'] == 0 ? 'no' : $response['data']) . ' result' . ($response['data'] > 1 ? 's' : '') . ' for the given query.'; + } } + return $response; } function getGranules() { - // error_log('getGranules GET: ' . json_encode($_GET)); + // TODO: simplify this $url = filter_var($_GET['url'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); $tableName = filter_var($_GET['tableName'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); $targetName = filter_var($_GET['targetName'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); @@ -116,42 +159,38 @@ function getGranules() { $filter = createFilter($targetName, $productTypes, $timeMin, $timeMax); $query = "SELECT TOP $limit * FROM $tableName $filter OFFSET $start"; // error_log('getGranules query: ' . $query); - $rows = request($url, $query); - - $visibleColumns = ['granule_uid', 'dataproduct_type', 'time_min', 'time_max', 'access_estsize', 'thumbnail_url', 'access_url']; - $names = ['dataproduct_type' => 'Type', 'access_estsize' => 'Size']; - $renderers = ['dataproduct_type' => 'type', 'time_min' => 'date', 'time_max' => 'date', 'access_estsize' => 'size', 'thumbnail_url' => 'img', 'access_url' => 'link', 'access_format' => 'format']; - $flexs = ['granule_uid' => 2]; - - $fields = array(); - $columns = array(); - foreach($rows[0] as $key => $value) { - $fields[] = ['name' => $key, 'type' => 'string']; - $columns[] = [ - 'dataIndex' => $key, - 'text' => array_key_exists($key, $names) ? $names[$key] : ucfirst(str_replace('_', ' ', $key)), - 'flex' => array_key_exists($key, $flexs) ? $flexs[$key] : 1, - 'hidden' => !in_array($key, $visibleColumns), - 'renderer' => array_key_exists($key, $renderers) ? $renderers[$key] : 'text' - ]; - } + $response = request($url, $query); + if($response['success']) { + $visibleColumns = ['granule_uid', 'dataproduct_type', 'time_min', 'time_max', 'access_estsize', 'thumbnail_url', 'access_url']; // rest are hidden + $names = ['dataproduct_type' => 'Type', 'access_estsize' => 'Size']; // default: pretty printed key name + $renderers = ['dataproduct_type' => 'type', 'time_min' => 'date', 'time_max' => 'date', 'access_estsize' => 'size', 'thumbnail_url' => 'img', 'access_url' => 'link', 'access_format' => 'format']; // default: text + $flexs = ['granule_uid' => 2]; // default: 1 + // $types = ['boolean' => , 'integer']; // TODO see http://php.net/manual/fr/function.gettype.php + + $fields = array(); + $columns = array(); + foreach($response['data'][0] as $key => $value) { + error_log('Granule ' . $key . ' is ' . gettype($value)); + $fields[] = ['name' => $key, 'type' => 'string']; + $columns[] = [ + 'dataIndex' => $key, + 'text' => array_key_exists($key, $names) ? $names[$key] : ucfirst(str_replace('_', ' ', $key)), + 'flex' => array_key_exists($key, $flexs) ? $flexs[$key] : 1, + 'hidden' => !in_array($key, $visibleColumns), + // 'type' => array_key_exists(gettype(), $types), + 'renderer' => array_key_exists($key, $renderers) ? $renderers[$key] : 'text' + ]; + } - $metadata = ['fields' => $fields, 'columns' => $columns, 'root' => 'data']; - return ['data' => $rows, 'total' => $nbRes, 'metaData' => $metadata]; + $response['total'] = $nbRes; + $response['metaData']['fields'] = $fields; + $response['metaData']['columns'] = $columns; + } + return $response; } // ----- utils ----- -function request($access_url, $query) { - $votMgr = new VOTableMgr; - $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; - $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode(preg_replace('/\s+/', ' ', $query)); // remove also multiple whitespaces - - $votMgr->load($url); - $result = $votMgr->parseStream(); - return $votMgr->getVotableError() ? array('error' => $votMgr->getVotableError()) : $result; -} - function createFilter($targetName, $productTypes, $timeMin, $timeMax) { $filter = array(); if($targetName) { -- libgit2 0.21.2