Commit a79b0198406e7a5a4b2265ff7d2ccf28a1c7c7a0
1 parent
73c7e8a5
Exists in
master
and in
112 other branches
Add EPN-TAP module (draft).
Showing
7 changed files
with
444 additions
and
2 deletions
Show diff stats
js/app/AmdaApp.js
... | ... | @@ -97,6 +97,13 @@ Ext.define('amdaApp.AmdaApp', { |
97 | 97 | source : 'amdaDesktop.InteropModule', |
98 | 98 | useLauncher : true |
99 | 99 | }, |
100 | + epntap : { | |
101 | + id : 'epntap-win', | |
102 | + icon : 'icon-epntap', | |
103 | + title : 'EPN-TAP data', | |
104 | + source : 'amdaDesktop.EpnTapModule', | |
105 | + useLauncher : true | |
106 | + }, | |
100 | 107 | info : { |
101 | 108 | id : 'info-win', |
102 | 109 | icon : 'icon-information', |
... | ... |
... | ... | @@ -0,0 +1,85 @@ |
1 | +/** | |
2 | + * Project : AMDA-NG | |
3 | + * Name : EpnTapModule.js | |
4 | + * @class amdaDesktop.EpnTapModule | |
5 | + * @extends amdaDesktop.AmdaModule | |
6 | + * @brief EpnTap Module controller definition | |
7 | + * @author Nathanael Jourdane | |
8 | + */ | |
9 | + | |
10 | +function onWindowLoaded() { | |
11 | +} | |
12 | + | |
13 | +function onSearchBtnClicked() { | |
14 | + var targetName = Ext.getCmp('targetNameCB').value; | |
15 | + var productType = Ext.getCmp('productTypeCB').value; | |
16 | + var startTime = Ext.getCmp('startTimeDF').rawValue; | |
17 | + var stopTime = Ext.getCmp('stopTimeDF').rawValue; | |
18 | + | |
19 | + for(let service of Ext.getCmp('servicesPanel').getStore().getRange()) { | |
20 | + var filter = Array(service.data.table_name, service.data.access_url, targetName, productType, startTime, stopTime); | |
21 | + AmdaAction.epnTapMgr('getServiceNbResults', filter, function(epnTapServices) { | |
22 | + service.set('nb_responses', epnTapServices); | |
23 | + // console.log(epnTapServices[1]); | |
24 | + }); | |
25 | + } | |
26 | +} | |
27 | + | |
28 | +// var grid = Ext.getCmp('servicesPanel'); | |
29 | +// var selection = grid.getSelectionModel(); | |
30 | +// access_url = []; | |
31 | +// table_name = []; | |
32 | +// for(i=0 ; i<grid.store.getCount() ; i++) { | |
33 | +// if(selection.isSelected(i)) { | |
34 | +// table_name.push(grid.store.getAt(i).data.table_name); | |
35 | +// access_url.push(grid.store.getAt(i).data.access_url); | |
36 | +// } | |
37 | +// | |
38 | +// } | |
39 | + | |
40 | +function onServiceSelected(service) { | |
41 | + var filter = Array(service['table_name'], service['access_url'], Ext.getCmp('targetNameCB').value, | |
42 | + Ext.getCmp('productTypeCB').value, Ext.getCmp('startTimeDF').rawValue, Ext.getCmp('stopTimeDF').rawValue); | |
43 | + | |
44 | + AmdaAction.epnTapMgr('getGranules', filter, function(granules) { | |
45 | + console.log(granules); | |
46 | + }); | |
47 | +} | |
48 | + | |
49 | +function onGranuleSelected(granule) { | |
50 | + console.log('selected granule: ' + granule.target_name); | |
51 | +} | |
52 | + | |
53 | +Ext.define('amdaDesktop.EpnTapModule', { | |
54 | + | |
55 | + extend: 'amdaDesktop.AmdaModule', | |
56 | + | |
57 | + requires: ['amdaUI.EpnTapUI'], | |
58 | + contentId : 'EpnTapUI', | |
59 | + | |
60 | + /** The alias name of the module view. */ | |
61 | + uiType: 'panelEpnTap', | |
62 | + | |
63 | + /** The text displayed on the *help button* tooltip. */ | |
64 | + helpTitle: 'Help on EPN-TAP Module', | |
65 | + | |
66 | + /** The name of the documentation file related to the module. */ | |
67 | + helpFile : 'epnTapHelp', | |
68 | + | |
69 | + width : 600, | |
70 | + height: 550, | |
71 | + | |
72 | + /** @class Module initialisation. */ | |
73 | + init: function() { | |
74 | + this.launcher = { | |
75 | + text: this.title, | |
76 | + iconCls: this.icon, | |
77 | + handler: this.createWindow, | |
78 | + scope: this | |
79 | + }; | |
80 | + this.onWindowLoaded = onWindowLoaded; | |
81 | + this.onSearchBtnClicked = onSearchBtnClicked; | |
82 | + this.onGranuleSelected = onGranuleSelected; | |
83 | + this.onServiceSelected = onServiceSelected; | |
84 | + } | |
85 | +}); | |
... | ... |
... | ... | @@ -0,0 +1,243 @@ |
1 | +/** | |
2 | + * Project: AMDA-NG | |
3 | + * Name: EpnTapUI.js | |
4 | + * @class amdaUI.EpnTapUI | |
5 | + * @extends Ext.tab.Panel | |
6 | + * @brief client for EPN-TAP services (View) | |
7 | + * @author Nathanael JOURDANE | |
8 | + * 24/10/2016: file creation | |
9 | + */ | |
10 | + | |
11 | +Ext.create('Ext.data.Store', { | |
12 | + storeId:'services_store', | |
13 | + fields: ['short_name', 'res_title', 'ivoid', 'access_url', 'table_name', 'content_type', | |
14 | + 'res_description', 'creator seq', 'content_level', 'reference_url', 'created', 'updated', 'nb_responses'], | |
15 | + proxy: { | |
16 | + type: 'ajax', | |
17 | + url: 'generic_data/EpnTapData/EpnTapServices.json', | |
18 | + reader: {type: 'json'} | |
19 | + }, | |
20 | + autoLoad: true | |
21 | +}); | |
22 | + | |
23 | +Ext.create('Ext.data.Store', { | |
24 | + storeId:'granules_store', | |
25 | + fields:['type', 'target_name', 'time_min', 'time_max'], | |
26 | + data: {'items': [ | |
27 | + {'type': 'sp', 'target_name': 'mars', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, | |
28 | + {'type': 'sp', 'target_name': 'mars', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, | |
29 | + {'type': 'im', 'target_name': 'earth', 'time_min': '01/01/2012', 'time_max': '02/01/2012'}, | |
30 | + {'type': 'im', 'target_name': 'earth', 'time_min': '01/01/2012', 'time_max': '02/01/2012'} | |
31 | + ]}, | |
32 | + proxy: { | |
33 | + type: 'memory', | |
34 | + reader: { type: 'json', root: 'items' } | |
35 | + } | |
36 | +}); | |
37 | + | |
38 | +Ext.create('Ext.data.Store', { | |
39 | + storeId:'productTypes_store', | |
40 | + fields: ['id', 'name'], | |
41 | + proxy: { | |
42 | + type: 'ajax', | |
43 | + url : 'generic_data/EpnTapData/EpnTapProductTypes.json', | |
44 | + reader: {type: 'json'} | |
45 | + }, | |
46 | + autoLoad: true | |
47 | +}); | |
48 | + | |
49 | +Ext.create('Ext.data.Store', { | |
50 | + storeId:'targetClasses_store', | |
51 | + fields: ['id', 'name'], | |
52 | + proxy: { | |
53 | + type: 'ajax', | |
54 | + url : 'generic_data/EpnTapData/EpnTapTargetClasses.json', | |
55 | + reader: { | |
56 | + type: 'json' | |
57 | + } | |
58 | + }, | |
59 | + autoLoad: true | |
60 | +}); | |
61 | + | |
62 | +Ext.create('Ext.data.Store', { | |
63 | + storeId: 'targetNames_store', | |
64 | + fields: ['n'], | |
65 | + proxy: { | |
66 | + type: 'ajax', | |
67 | + url : 'generic_data/EpnTapData/EpnTapTargetNames.json', | |
68 | + reader: {type: 'json'} | |
69 | + }, | |
70 | + autoLoad: true | |
71 | +}); | |
72 | + | |
73 | +var serviceFilterPanel = { | |
74 | + id: 'serviceFilterPanel', | |
75 | + xtype: 'panel', | |
76 | + region : 'north', | |
77 | + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
78 | + defaults: { margin: 5 }, | |
79 | + items: [{ // Left part | |
80 | + xtype : 'container', | |
81 | + layout: 'form', | |
82 | + flex: 2, | |
83 | + items: [{ | |
84 | + id: 'productTypeCB', | |
85 | + xtype: 'combobox', | |
86 | + fieldLabel: 'Product type', | |
87 | + store: Ext.data.StoreManager.lookup('productTypes_store'), | |
88 | + queryMode: 'local', | |
89 | + displayField: 'name', | |
90 | + valueField: 'id', | |
91 | + name: 'productType', | |
92 | + editable: false, | |
93 | + allowBlank: false | |
94 | + }, { | |
95 | + id: 'targetClassCB', | |
96 | + xtype: 'combobox', | |
97 | + fieldLabel: 'Target class', | |
98 | + store: Ext.data.StoreManager.lookup('targetClasses_store'), | |
99 | + queryMode: 'local', | |
100 | + displayField: 'name', | |
101 | + valueField: 'id', | |
102 | + name: 'targetClass', | |
103 | + editable: false, | |
104 | + allowBlank: false | |
105 | + }, { | |
106 | + id: 'targetNameCB', | |
107 | + xtype: 'combobox', | |
108 | + fieldLabel: 'Target name', | |
109 | + store: Ext.data.StoreManager.lookup('targetNames_store'), | |
110 | + queryMode: 'local', | |
111 | + displayField: 'n', | |
112 | + valueField: 'n', | |
113 | + name: 'targetName', | |
114 | + allowBlank: false, | |
115 | + triggerAction: 'all', | |
116 | + typeAhead: true, | |
117 | + mode: 'remote', | |
118 | + minChars: 2, | |
119 | + forceSelection: true | |
120 | + // listeners: { | |
121 | + // scope: window, | |
122 | + // 'change': function(combobox, newValue, oldValue, eOpts) { | |
123 | + // if(newValue && newValue.length >= 3) { | |
124 | + // myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onTargetNameUpdate(newValue); | |
125 | + // } | |
126 | + // } | |
127 | + // } | |
128 | + }] | |
129 | + }, { // Right part | |
130 | + xtype : 'container', | |
131 | + layout: 'form', | |
132 | + flex: 2, | |
133 | + items: [{ | |
134 | + id: 'startTimeDF', | |
135 | + xtype: 'datefield', | |
136 | + fieldLabel: 'Start time', | |
137 | + name: 'start_time', | |
138 | + allowBlank:false | |
139 | + }, { | |
140 | + id: 'stopTimeDF', | |
141 | + xtype: 'datefield', | |
142 | + fieldLabel: 'Stop time', | |
143 | + name: 'stop_time', | |
144 | + allowBlank:false | |
145 | + }, { | |
146 | + id: 'searchServicesBtn', | |
147 | + xtype: 'button', | |
148 | + text: 'Search services', | |
149 | + handler: function() { | |
150 | + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onSearchBtnClicked(); | |
151 | + } | |
152 | + }] | |
153 | + }] | |
154 | +} | |
155 | + | |
156 | +var servicesPanel = { | |
157 | + id: 'servicesPanel', | |
158 | + xtype : 'grid', | |
159 | + title: 'Services', | |
160 | + multiSelect: true, | |
161 | + store: Ext.data.StoreManager.lookup('services_store'), | |
162 | + flex: 1, | |
163 | + columns: [ | |
164 | + { text: 'Service', dataIndex: 'short_name', flex: 3 }, | |
165 | + { text: 'Results', dataIndex: 'nb_responses', flex: 1} | |
166 | + ], | |
167 | + listeners: { | |
168 | + 'cellclick': function(grid, td, cellIndex, record, tr, rowIndex, e, eOpts) { | |
169 | + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onServiceSelected(record.data); | |
170 | + } | |
171 | + } | |
172 | +} | |
173 | + | |
174 | +var granulesPanel = { | |
175 | + id: 'granulesPanel', | |
176 | + xtype : 'grid', | |
177 | + title: 'Granules', | |
178 | + store: Ext.data.StoreManager.lookup('granulesStore'), | |
179 | + flex: 3, | |
180 | + columns: [ | |
181 | + { text: 'Type', dataIndex: 'type', flex: 1 }, | |
182 | + { text: 'Target', dataIndex: 'target_name', flex: 1 }, | |
183 | + { text: 'Time min', dataIndex: 'time_min', flex: 2 }, | |
184 | + { text: 'Time max', dataIndex: 'time_max', flex: 2 } | |
185 | + ], | |
186 | + listeners: { | |
187 | + 'cellclick': function(grid, td, cellIndex, record, tr, rowIndex, e, eOpts) { | |
188 | + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onGranuleSelected(record.data); | |
189 | + } | |
190 | + } | |
191 | +} | |
192 | + | |
193 | +var mainPanel = { | |
194 | + id: 'mainPanel', | |
195 | + xtype: 'panel', | |
196 | + region: 'center', | |
197 | + height: 350, | |
198 | + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
199 | + items: [ servicesPanel, granulesPanel ], | |
200 | + listeners: { | |
201 | + afterrender: function() { | |
202 | + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).onWindowLoaded(); | |
203 | + } | |
204 | + } | |
205 | +} | |
206 | + | |
207 | +var infoPanel = { | |
208 | + id: 'infoPanel', | |
209 | + xtype : 'panel', | |
210 | + region: 'south', | |
211 | + title: 'Information', | |
212 | + collapsible: true, | |
213 | + flex: 0, | |
214 | + height: 100, | |
215 | + autoHide: false, | |
216 | + bodyStyle: 'padding: 5px', | |
217 | + iconCls: 'icon-information', | |
218 | + loader: { autoLoad: true, url: helpDir + 'epnTapHOWTO' } | |
219 | +} | |
220 | + | |
221 | +Ext.define('amdaUI.EpnTapUI', { | |
222 | + extend: 'Ext.container.Container', | |
223 | + alias: 'widget.panelEpnTap', | |
224 | + | |
225 | + constructor: function(config) { | |
226 | + this.init(config); | |
227 | + this.callParent(arguments); | |
228 | + }, | |
229 | + | |
230 | + init : function(config) { | |
231 | + var myConf = { | |
232 | + width: 600, | |
233 | + height: 550, | |
234 | + layout: 'border', | |
235 | + items: [ | |
236 | + serviceFilterPanel, | |
237 | + mainPanel, | |
238 | + infoPanel | |
239 | + ] | |
240 | + }; | |
241 | + Ext.apply(this, Ext.apply(arguments, myConf)); | |
242 | + } | |
243 | +}); | |
... | ... |
3.21 KB
php/classes/AmdaAction.php
... | ... | @@ -1334,7 +1334,10 @@ class AmdaAction { |
1334 | 1334 | $alreadyUsed = $mgr->isNameAlreadyUsed($obj->type, $obj->name); |
1335 | 1335 | return array('success' => true, 'alreadyUsed' => $alreadyUsed); |
1336 | 1336 | } |
1337 | - | |
1337 | + | |
1338 | + public function epnTapMgr($function_name, $args) { | |
1339 | + return (new EpnTapMgr)->call($function_name, $args); | |
1340 | + } | |
1338 | 1341 | } |
1339 | 1342 | ?> |
1340 | 1343 | |
... | ... |
... | ... | @@ -0,0 +1,100 @@ |
1 | +<?php | |
2 | +/** @class EpnTapMgr | |
3 | +* @brief Manager to communicates with EPN-TAP services. | |
4 | +*/ | |
5 | + | |
6 | +class EpnTapMgr { | |
7 | + | |
8 | + public function call($function_name, $args) { | |
9 | + switch($function_name) { | |
10 | + case 'getServiceNbResults': | |
11 | + if(count($args) == 6) | |
12 | + return $this->getServiceNbResults($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); | |
13 | + break; | |
14 | + case 'getGranules': | |
15 | + if(count($args) == 6) | |
16 | + return $this->getGranules($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); | |
17 | + break; | |
18 | + default: | |
19 | + return array('success' => false, 'message' => $function_name.' is an unknown function.'); | |
20 | + break; | |
21 | + } | |
22 | + return array('success' => false, 'message' => 'The function do not have the required number of arguments'); | |
23 | + } | |
24 | + | |
25 | + // 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 | |
26 | + // select distinct target_name from xxx.epn_core | |
27 | + | |
28 | + private function date2JD($date) { | |
29 | + list($month, $day, $year) = split('[/.-]', $date); | |
30 | + | |
31 | + if($month == 1 || $month == 2) { | |
32 | + $yearp = $year - 1; | |
33 | + $monthp = $month + 12; | |
34 | + } else { | |
35 | + $yearp = $year; | |
36 | + $monthp = $month; | |
37 | + } | |
38 | + | |
39 | + # this checks where we are in relation to October 15, 1582, the beginning | |
40 | + # of the Gregorian calendar. | |
41 | + if (($year < 1582) || | |
42 | + ($year == 1582 && $month < 10) || | |
43 | + ($year == 1582 && $month == 10 && $day < 15)) | |
44 | + $j_day = 0; | |
45 | + else | |
46 | + $j_day = 2 - (int)($yearp / 100.0) + (int)((int)($yearp / 100.0) / 4.0); | |
47 | + | |
48 | + $j_day += $yearp < 0 ? (int)((365.25 * $yearp) - 0.75) : (int)(365.25 * $yearp); | |
49 | + $j_day += (int)(30.6001 * ($monthp + 1)) + $day + 1720994.5; | |
50 | + | |
51 | + return $j_day; | |
52 | + } | |
53 | + | |
54 | + private function getServiceNbResults($table_name, $access_url, $target_name, $dataproduct_type, $time_min, $time_max) { | |
55 | + $filter = array(); | |
56 | + if($target_name) | |
57 | + array_push($filter, "target_name = '$target_name'"); | |
58 | + if($dataproduct_type) | |
59 | + array_push($filter, "dataproduct_type = '$dataproduct_type'"); | |
60 | + if($time_min) | |
61 | + array_push($filter, "time_min >= " . $this->date2JD($time_min)); | |
62 | + if($time_max) | |
63 | + array_push($filter, "time_max >= " . $this->date2JD($time_max)); | |
64 | + | |
65 | + $query = "SELECT COUNT(granule_uid) AS nb_results FROM $table_name" | |
66 | + . ($filter.length > 0 ? ' WHERE ' . join(' AND ', $filter) : ''); | |
67 | + | |
68 | + $votMgr = new VOTableMgr; | |
69 | + $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; | |
70 | + $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode($query); | |
71 | + $votMgr->load($url); | |
72 | + return $votMgr->isValidSchema() ? $votMgr->getSimpleInteger() : 0; | |
73 | + } | |
74 | + | |
75 | + static function getGranules($table_name, $access_url) { | |
76 | + $filter = array(); | |
77 | + if($target_name) | |
78 | + array_push($filter, "target_name = '$target_name'"); | |
79 | + if($dataproduct_type) | |
80 | + array_push($filter, "dataproduct_type = '$dataproduct_type'"); | |
81 | + if($time_min) | |
82 | + array_push($filter, "time_min >= " . $this->date2JD($time_min)); | |
83 | + if($time_max) | |
84 | + array_push($filter, "time_max >= " . $this->date2JD($time_max)); | |
85 | + | |
86 | + $query = "SELECT dataproduct_type, target_name, time_min, time_max FROM $table_name" | |
87 | + . ($filter.length > 0 ? ' WHERE ' . join(' AND ', $filter) : ''); | |
88 | + | |
89 | + $votMgr = new VOTableMgr; | |
90 | + $params = 'FORMAT=votable&LANG=ADQL&REQUEST=doQuery'; | |
91 | + $url = $access_url . '/sync?' . $params . '&QUERY=' . urlencode($query); | |
92 | + $votMgr->load($url); | |
93 | + if($votMgr->isValidSchema()) { | |
94 | + return false; | |
95 | + } else { | |
96 | + return true; | |
97 | + } | |
98 | + } | |
99 | +} | |
100 | +?> | |
... | ... |
php/config.php
... | ... | @@ -137,6 +137,9 @@ define('PREDEFINED',BASE_PATH.'amda_plus/predefined/'); |
137 | 137 | define('PRO',BASE_PATH.'amda_plus/pro/'); |
138 | 138 | define('specialGrpsXml',SpecialSettingsDir.'Groups.xml'); |
139 | 139 | |
140 | +// EPN-TAP data | |
141 | +define('EpnTapDataPath', DATAPATH.'EpnTapData/'); | |
142 | + | |
140 | 143 | //Help info dirs |
141 | 144 | define('HELPPATH', BASE_PATH."help/"); |
142 | 145 | define('targetsSimu',HELPPATH.'simu/TargetsSimu.xml'); |
... | ... | @@ -380,7 +383,8 @@ $API = array( |
380 | 383 | ), |
381 | 384 | 'isSharedObjectNameAlreadyUsed' => array( |
382 | 385 | 'len'=>1 |
383 | - ) | |
386 | + ), | |
387 | + 'epnTapMgr' => array('len'=>2) | |
384 | 388 | ) |
385 | 389 | ) |
386 | 390 | ); |
... | ... |