From a79b0198406e7a5a4b2265ff7d2ccf28a1c7c7a0 Mon Sep 17 00:00:00 2001 From: Nathanael Jourdane <nathanael.jourdane@irap.omp.eu> Date: Wed, 23 Nov 2016 12:04:44 +0100 Subject: [PATCH] Add EPN-TAP module (draft). --- js/app/AmdaApp.js | 7 +++++++ js/app/controllers/EpnTapModule.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ js/app/views/EpnTapUI.js | 243 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ js/resources/images/64x64/epntap.png | Bin 0 -> 3284 bytes php/classes/AmdaAction.php | 5 ++++- php/classes/EpnTapMgr.php | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ php/config.php | 6 +++++- 7 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 js/app/controllers/EpnTapModule.js create mode 100644 js/app/views/EpnTapUI.js create mode 100644 js/resources/images/64x64/epntap.png create mode 100644 php/classes/EpnTapMgr.php diff --git a/js/app/AmdaApp.js b/js/app/AmdaApp.js index 7ea6130..3b8c401 100755 --- a/js/app/AmdaApp.js +++ b/js/app/AmdaApp.js @@ -97,6 +97,13 @@ Ext.define('amdaApp.AmdaApp', { source : 'amdaDesktop.InteropModule', useLauncher : true }, + epntap : { + id : 'epntap-win', + icon : 'icon-epntap', + title : 'EPN-TAP data', + source : 'amdaDesktop.EpnTapModule', + useLauncher : true + }, info : { id : 'info-win', icon : 'icon-information', diff --git a/js/app/controllers/EpnTapModule.js b/js/app/controllers/EpnTapModule.js new file mode 100644 index 0000000..8bc58a5 --- /dev/null +++ b/js/app/controllers/EpnTapModule.js @@ -0,0 +1,85 @@ +/** + * Project : AMDA-NG + * Name : EpnTapModule.js + * @class amdaDesktop.EpnTapModule + * @extends amdaDesktop.AmdaModule + * @brief EpnTap Module controller definition + * @author Nathanael Jourdane + */ + +function onWindowLoaded() { +} + +function onSearchBtnClicked() { + var targetName = Ext.getCmp('targetNameCB').value; + var productType = Ext.getCmp('productTypeCB').value; + var startTime = Ext.getCmp('startTimeDF').rawValue; + var stopTime = Ext.getCmp('stopTimeDF').rawValue; + + for(let service of Ext.getCmp('servicesPanel').getStore().getRange()) { + var filter = Array(service.data.table_name, service.data.access_url, targetName, productType, startTime, stopTime); + AmdaAction.epnTapMgr('getServiceNbResults', filter, function(epnTapServices) { + service.set('nb_responses', epnTapServices); + // console.log(epnTapServices[1]); + }); + } +} + +// var grid = Ext.getCmp('servicesPanel'); +// var selection = grid.getSelectionModel(); +// access_url = []; +// table_name = []; +// for(i=0 ; i<grid.store.getCount() ; i++) { +// if(selection.isSelected(i)) { +// table_name.push(grid.store.getAt(i).data.table_name); +// access_url.push(grid.store.getAt(i).data.access_url); +// } +// +// } + +function onServiceSelected(service) { + var filter = Array(service['table_name'], service['access_url'], Ext.getCmp('targetNameCB').value, + Ext.getCmp('productTypeCB').value, Ext.getCmp('startTimeDF').rawValue, Ext.getCmp('stopTimeDF').rawValue); + + AmdaAction.epnTapMgr('getGranules', filter, function(granules) { + console.log(granules); + }); +} + +function onGranuleSelected(granule) { + console.log('selected granule: ' + granule.target_name); +} + +Ext.define('amdaDesktop.EpnTapModule', { + + extend: 'amdaDesktop.AmdaModule', + + requires: ['amdaUI.EpnTapUI'], + contentId : 'EpnTapUI', + + /** The alias name of the module view. */ + uiType: 'panelEpnTap', + + /** The text displayed on the *help button* tooltip. */ + helpTitle: 'Help on EPN-TAP Module', + + /** The name of the documentation file related to the module. */ + helpFile : 'epnTapHelp', + + width : 600, + height: 550, + + /** @class Module initialisation. */ + init: function() { + this.launcher = { + text: this.title, + iconCls: this.icon, + handler: this.createWindow, + scope: this + }; + this.onWindowLoaded = onWindowLoaded; + this.onSearchBtnClicked = onSearchBtnClicked; + this.onGranuleSelected = onGranuleSelected; + this.onServiceSelected = onServiceSelected; + } +}); diff --git a/js/app/views/EpnTapUI.js b/js/app/views/EpnTapUI.js new file mode 100644 index 0000000..4623846 --- /dev/null +++ b/js/app/views/EpnTapUI.js @@ -0,0 +1,243 @@ +/** + * Project: AMDA-NG + * Name: EpnTapUI.js + * @class amdaUI.EpnTapUI + * @extends Ext.tab.Panel + * @brief client for EPN-TAP services (View) + * @author Nathanael JOURDANE + * 24/10/2016: file creation + */ + +Ext.create('Ext.data.Store', { + storeId:'services_store', + fields: ['short_name', 'res_title', 'ivoid', 'access_url', 'table_name', 'content_type', + 'res_description', 'creator seq', 'content_level', 'reference_url', 'created', 'updated', 'nb_responses'], + proxy: { + type: 'ajax', + url: 'generic_data/EpnTapData/EpnTapServices.json', + reader: {type: 'json'} + }, + autoLoad: true +}); + +Ext.create('Ext.data.Store', { + storeId:'granules_store', + fields:['type', 'target_name', 'time_min', 'time_max'], + data: {'items': [ + {'type': 'sp', 'target_name': 'mars', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, + {'type': 'sp', 'target_name': 'mars', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, + {'type': 'im', 'target_name': 'earth', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, + {'type': 'im', 'target_name': 'earth', 'time_min': '01/01/2012', 'time_max': '02/01/2012'} + ]}, + proxy: { + type: 'memory', + reader: { type: 'json', root: 'items' } + } +}); + +Ext.create('Ext.data.Store', { + storeId:'productTypes_store', + fields: ['id', 'name'], + proxy: { + type: 'ajax', + url : 'generic_data/EpnTapData/EpnTapProductTypes.json', + reader: {type: 'json'} + }, + autoLoad: true +}); + +Ext.create('Ext.data.Store', { + storeId:'targetClasses_store', + fields: ['id', 'name'], + proxy: { + type: 'ajax', + url : 'generic_data/EpnTapData/EpnTapTargetClasses.json', + reader: { + type: 'json' + } + }, + autoLoad: true +}); + +Ext.create('Ext.data.Store', { + storeId: 'targetNames_store', + fields: ['n'], + proxy: { + type: 'ajax', + url : 'generic_data/EpnTapData/EpnTapTargetNames.json', + reader: {type: 'json'} + }, + autoLoad: true +}); + +var serviceFilterPanel = { + id: 'serviceFilterPanel', + xtype: 'panel', + region : 'north', + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, + defaults: { margin: 5 }, + items: [{ // Left part + xtype : 'container', + layout: 'form', + flex: 2, + items: [{ + id: 'productTypeCB', + xtype: 'combobox', + fieldLabel: 'Product type', + store: Ext.data.StoreManager.lookup('productTypes_store'), + queryMode: 'local', + displayField: 'name', + valueField: 'id', + name: 'productType', + editable: false, + allowBlank: false + }, { + id: 'targetClassCB', + xtype: 'combobox', + fieldLabel: 'Target class', + store: Ext.data.StoreManager.lookup('targetClasses_store'), + queryMode: 'local', + displayField: 'name', + valueField: 'id', + name: 'targetClass', + editable: false, + allowBlank: false + }, { + id: 'targetNameCB', + xtype: 'combobox', + fieldLabel: 'Target name', + store: Ext.data.StoreManager.lookup('targetNames_store'), + queryMode: 'local', + displayField: 'n', + valueField: 'n', + name: 'targetName', + allowBlank: false, + triggerAction: 'all', + typeAhead: true, + mode: 'remote', + minChars: 2, + forceSelection: true + // listeners: { + // scope: window, + // 'change': function(combobox, newValue, oldValue, eOpts) { + // if(newValue && newValue.length >= 3) { + // myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onTargetNameUpdate(newValue); + // } + // } + // } + }] + }, { // Right part + xtype : 'container', + layout: 'form', + flex: 2, + items: [{ + id: 'startTimeDF', + xtype: 'datefield', + fieldLabel: 'Start time', + name: 'start_time', + allowBlank:false + }, { + id: 'stopTimeDF', + xtype: 'datefield', + fieldLabel: 'Stop time', + name: 'stop_time', + allowBlank:false + }, { + id: 'searchServicesBtn', + xtype: 'button', + text: 'Search services', + handler: function() { + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onSearchBtnClicked(); + } + }] + }] +} + +var servicesPanel = { + id: 'servicesPanel', + xtype : 'grid', + title: 'Services', + multiSelect: true, + store: Ext.data.StoreManager.lookup('services_store'), + flex: 1, + columns: [ + { text: 'Service', dataIndex: 'short_name', flex: 3 }, + { text: 'Results', dataIndex: 'nb_responses', flex: 1} + ], + listeners: { + 'cellclick': function(grid, td, cellIndex, record, tr, rowIndex, e, eOpts) { + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onServiceSelected(record.data); + } + } +} + +var granulesPanel = { + id: 'granulesPanel', + xtype : 'grid', + title: 'Granules', + store: Ext.data.StoreManager.lookup('granulesStore'), + flex: 3, + columns: [ + { text: 'Type', dataIndex: 'type', flex: 1 }, + { text: 'Target', dataIndex: 'target_name', flex: 1 }, + { text: 'Time min', dataIndex: 'time_min', flex: 2 }, + { text: 'Time max', dataIndex: 'time_max', flex: 2 } + ], + listeners: { + 'cellclick': function(grid, td, cellIndex, record, tr, rowIndex, e, eOpts) { + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onGranuleSelected(record.data); + } + } +} + +var mainPanel = { + id: 'mainPanel', + xtype: 'panel', + region: 'center', + height: 350, + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, + items: [ servicesPanel, granulesPanel ], + listeners: { + afterrender: function() { + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onWindowLoaded(); + } + } +} + +var infoPanel = { + id: 'infoPanel', + xtype : 'panel', + region: 'south', + title: 'Information', + collapsible: true, + flex: 0, + height: 100, + autoHide: false, + bodyStyle: 'padding: 5px', + iconCls: 'icon-information', + loader: { autoLoad: true, url: helpDir + 'epnTapHOWTO' } +} + +Ext.define('amdaUI.EpnTapUI', { + extend: 'Ext.container.Container', + alias: 'widget.panelEpnTap', + + constructor: function(config) { + this.init(config); + this.callParent(arguments); + }, + + init : function(config) { + var myConf = { + width: 600, + height: 550, + layout: 'border', + items: [ + serviceFilterPanel, + mainPanel, + infoPanel + ] + }; + Ext.apply(this, Ext.apply(arguments, myConf)); + } +}); diff --git a/js/resources/images/64x64/epntap.png b/js/resources/images/64x64/epntap.png new file mode 100644 index 0000000..c749a1e Binary files /dev/null and b/js/resources/images/64x64/epntap.png differ diff --git a/php/classes/AmdaAction.php b/php/classes/AmdaAction.php index 297cd5a..fd8ac52 100644 --- a/php/classes/AmdaAction.php +++ b/php/classes/AmdaAction.php @@ -1334,7 +1334,10 @@ class AmdaAction { $alreadyUsed = $mgr->isNameAlreadyUsed($obj->type, $obj->name); return array('success' => true, 'alreadyUsed' => $alreadyUsed); } - + + public function epnTapMgr($function_name, $args) { + return (new EpnTapMgr)->call($function_name, $args); + } } ?> diff --git a/php/classes/EpnTapMgr.php b/php/classes/EpnTapMgr.php new file mode 100644 index 0000000..ef03603 --- /dev/null +++ b/php/classes/EpnTapMgr.php @@ -0,0 +1,100 @@ +<?php +/** @class EpnTapMgr +* @brief Manager to communicates with EPN-TAP services. +*/ + +class EpnTapMgr { + + public function call($function_name, $args) { + switch($function_name) { + case 'getServiceNbResults': + if(count($args) == 6) + return $this->getServiceNbResults($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); + break; + case 'getGranules': + if(count($args) == 6) + return $this->getGranules($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); + break; + default: + return array('success' => false, 'message' => $function_name.' is an unknown function.'); + break; + } + return array('success' => false, 'message' => 'The function do not have the required number of arguments'); + } + + // dc.zah.uni-heidelberg.de/tap/sync?FORMAT=votable&LANG=ADQL&QUERY=SELECT DISTINCT table_name WHERE standard_id='ivo://ivoa.net/std/tap' AND intf_type='vs:paramhttp' AND detail_xpath='/capability/dataModel/@ivo-id' FROM&REQUEST=doQuery + // select distinct target_name from xxx.epn_core + + private function date2JD($date) { + list($month, $day, $year) = split('[/.-]', $date); + + if($month == 1 || $month == 2) { + $yearp = $year - 1; + $monthp = $month + 12; + } else { + $yearp = $year; + $monthp = $month; + } + + # this checks where we are in relation to October 15, 1582, the beginning + # of the Gregorian calendar. + if (($year < 1582) || + ($year == 1582 && $month < 10) || + ($year == 1582 && $month == 10 && $day < 15)) + $j_day = 0; + else + $j_day = 2 - (int)($yearp / 100.0) + (int)((int)($yearp / 100.0) / 4.0); + + $j_day += $yearp < 0 ? (int)((365.25 * $yearp) - 0.75) : (int)(365.25 * $yearp); + $j_day += (int)(30.6001 * ($monthp + 1)) + $day + 1720994.5; + + return $j_day; + } + + private function getServiceNbResults($table_name, $access_url, $target_name, $dataproduct_type, $time_min, $time_max) { + $filter = array(); + if($target_name) + array_push($filter, "target_name = '$target_name'"); + if($dataproduct_type) + array_push($filter, "dataproduct_type = '$dataproduct_type'"); + if($time_min) + array_push($filter, "time_min >= " . $this->date2JD($time_min)); + if($time_max) + array_push($filter, "time_max >= " . $this->date2JD($time_max)); + + $query = "SELECT COUNT(granule_uid) AS nb_results FROM $table_name" + . ($filter.length > 0 ? ' WHERE ' . join(' AND ', $filter) : ''); + + $votMgr = new VOTableMgr; + $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; + $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode($query); + $votMgr->load($url); + return $votMgr->isValidSchema() ? $votMgr->getSimpleInteger() : 0; + } + + static function getGranules($table_name, $access_url) { + $filter = array(); + if($target_name) + array_push($filter, "target_name = '$target_name'"); + if($dataproduct_type) + array_push($filter, "dataproduct_type = '$dataproduct_type'"); + if($time_min) + array_push($filter, "time_min >= " . $this->date2JD($time_min)); + if($time_max) + array_push($filter, "time_max >= " . $this->date2JD($time_max)); + + $query = "SELECT dataproduct_type, target_name, time_min, time_max FROM $table_name" + . ($filter.length > 0 ? ' WHERE ' . join(' AND ', $filter) : ''); + + $votMgr = new VOTableMgr; + $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; + $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode($query); + $votMgr->load($url); + if($votMgr->isValidSchema()) { + return false; + } else { + return true; + } + } +} +?> diff --git a/php/config.php b/php/config.php index 0e5417b..87e1aa1 100644 --- a/php/config.php +++ b/php/config.php @@ -137,6 +137,9 @@ define('PREDEFINED',BASE_PATH.'amda_plus/predefined/'); define('PRO',BASE_PATH.'amda_plus/pro/'); define('specialGrpsXml',SpecialSettingsDir.'Groups.xml'); +// EPN-TAP data +define('EpnTapDataPath', DATAPATH.'EpnTapData/'); + //Help info dirs define('HELPPATH', BASE_PATH."help/"); define('targetsSimu',HELPPATH.'simu/TargetsSimu.xml'); @@ -380,7 +383,8 @@ $API = array( ), 'isSharedObjectNameAlreadyUsed' => array( 'len'=>1 - ) + ), + 'epnTapMgr' => array('len'=>2) ) ) ); -- libgit2 0.21.2