mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 22:06:53 +08:00
Remove sample tracking manual external service transfer due to security concerns
This commit is contained in:
@@ -25,11 +25,6 @@ from sqlalchemy.ext import hybrid
|
||||
from sqlalchemy import types
|
||||
from sqlalchemy import type_coerce
|
||||
|
||||
try:
|
||||
import pexpect
|
||||
except ImportError:
|
||||
pexpect = None
|
||||
|
||||
import galaxy.model.orm.now
|
||||
import galaxy.model.metadata
|
||||
import galaxy.security.passwords
|
||||
@@ -60,9 +55,6 @@ _datatypes_registry = None
|
||||
# this be unlimited - filter in Python if over this limit.
|
||||
MAX_IN_FILTER_LENGTH = 100
|
||||
|
||||
PEXPECT_IMPORT_MESSAGE = ('The Python pexpect package is required to use this '
|
||||
'feature, please install it')
|
||||
|
||||
|
||||
class NoConverterException(Exception):
|
||||
def __init__(self, value):
|
||||
@@ -4621,30 +4613,6 @@ class Sample( object, Dictifiable ):
|
||||
untransferred_datasets.append( dataset )
|
||||
return untransferred_datasets
|
||||
|
||||
def get_untransferred_dataset_size( self, filepath, scp_configs ):
|
||||
def print_ticks( d ):
|
||||
pass
|
||||
if pexpect is None:
|
||||
return PEXPECT_IMPORT_MESSAGE
|
||||
error_msg = 'Error encountered in determining the file size of %s on the external_service.' % filepath
|
||||
if not scp_configs['host'] or not scp_configs['user_name'] or not scp_configs['password']:
|
||||
return error_msg
|
||||
login_str = '%s@%s' % ( scp_configs['user_name'], scp_configs['host'] )
|
||||
cmd = 'ssh %s "du -sh \'%s\'"' % ( login_str, filepath )
|
||||
try:
|
||||
output = pexpect.run( cmd,
|
||||
events={ '.ssword:*': scp_configs['password'] + '\r\n',
|
||||
pexpect.TIMEOUT: print_ticks},
|
||||
timeout=10 )
|
||||
except Exception:
|
||||
return error_msg
|
||||
# cleanup the output to get just the file size
|
||||
return output.replace( filepath, '' )\
|
||||
.replace( 'Password:', '' )\
|
||||
.replace( "'s password:", '' )\
|
||||
.replace( login_str, '' )\
|
||||
.strip()
|
||||
|
||||
@property
|
||||
def run_details( self ):
|
||||
# self.runs is a list of SampleRunAssociations ordered descending on update_time.
|
||||
|
||||
@@ -9,15 +9,7 @@ from galaxy.web.form_builder import build_select_field
|
||||
from galaxy.web.framework.helpers import time_ago, grids
|
||||
from .requests_common import RequestsGrid, invalid_id_redirect
|
||||
from markupsafe import escape
|
||||
import amqp
|
||||
|
||||
try:
|
||||
import pexpect
|
||||
except ImportError:
|
||||
pexpect = None
|
||||
|
||||
PEXPECT_IMPORT_MESSAGE = ('The Python pexpect package is required to use this '
|
||||
'feature, please install it')
|
||||
|
||||
log = logging.getLogger( __name__ )
|
||||
|
||||
@@ -371,207 +363,6 @@ class RequestsAdmin( BaseUIController, UsesFormDefinitionsMixin ):
|
||||
action='manage_datasets',
|
||||
sample_id=sample_id ) )
|
||||
|
||||
@web.expose
|
||||
@web.require_admin
|
||||
def select_datasets_to_transfer( self, trans, **kwd ):
|
||||
params = util.Params( kwd )
|
||||
message = util.restore_text( params.get( 'message', '' ) )
|
||||
status = params.get( 'status', 'done' )
|
||||
request_id = kwd.get( 'request_id', None )
|
||||
external_service_id = kwd.get( 'external_service_id', None )
|
||||
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
|
||||
external_service = trans.sa_session.query( trans.model.ExternalService ).get( trans.security.decode_id( external_service_id ) )
|
||||
# Load the data transfer settings
|
||||
external_service.load_data_transfer_settings( trans )
|
||||
scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_protocol.SCP ]
|
||||
selected_datasets_to_transfer = util.restore_text( params.get( 'selected_datasets_to_transfer', '' ) )
|
||||
if selected_datasets_to_transfer:
|
||||
selected_datasets_to_transfer = selected_datasets_to_transfer.split(',')
|
||||
else:
|
||||
selected_datasets_to_transfer = []
|
||||
sample_id = kwd.get( 'sample_id', 'none' )
|
||||
sample_id_select_field = self.__build_sample_id_select_field( trans, request, sample_id )
|
||||
if sample_id != 'none':
|
||||
sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( sample_id ) )
|
||||
else:
|
||||
sample = None
|
||||
# The __get_files() method redirects here with a status of 'error' and a message if there
|
||||
# was a problem retrieving the files.
|
||||
if params.get( 'select_datasets_to_transfer_button', False ):
|
||||
# Get the sample that was sequenced to produce these datasets.
|
||||
if sample_id == 'none':
|
||||
del kwd[ 'select_datasets_to_transfer_button' ]
|
||||
message = 'Select the sample that was sequenced to produce the datasets you want to transfer.'
|
||||
kwd[ 'message' ] = message
|
||||
kwd[ 'status' ] = 'error'
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_admin',
|
||||
action='select_datasets_to_transfer',
|
||||
**kwd ) )
|
||||
if not sample.library:
|
||||
# Display an error if a sample has been selected that
|
||||
# has not yet been associated with a destination library.
|
||||
message = 'Select a target data library and folder for the sample before selecting the datasets.'
|
||||
status = 'error'
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_common',
|
||||
action='edit_samples',
|
||||
cntrller='requests_admin',
|
||||
id=trans.security.encode_id( request.id ),
|
||||
status=status,
|
||||
message=message ) )
|
||||
# Save the sample datasets
|
||||
sample_dataset_file_names = self.__create_sample_datasets( trans, sample, selected_datasets_to_transfer, external_service )
|
||||
if sample_dataset_file_names:
|
||||
message = 'Datasets (%s) have been selected for sample (%s)' % \
|
||||
( str( sample_dataset_file_names )[1:-1].replace( "'", "" ), sample.name )
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_admin',
|
||||
action='manage_datasets',
|
||||
request_id=request_id,
|
||||
sample_id=sample_id,
|
||||
message=message,
|
||||
status=status ) )
|
||||
return trans.fill_template( '/admin/requests/select_datasets_to_transfer.mako',
|
||||
cntrller='requests_admin',
|
||||
request=request,
|
||||
external_service=external_service,
|
||||
scp_configs=scp_configs,
|
||||
sample=sample,
|
||||
sample_id_select_field=sample_id_select_field,
|
||||
status=status,
|
||||
message=message )
|
||||
|
||||
@web.json
|
||||
def get_file_details( self, trans, request_id, external_service_id, folder_path ):
|
||||
def print_ticks( d ):
|
||||
# pexpect timeout method
|
||||
pass
|
||||
# Avoid caching
|
||||
trans.response.headers['Pragma'] = 'no-cache'
|
||||
trans.response.headers['Expires'] = '0'
|
||||
if pexpect is None:
|
||||
return PEXPECT_IMPORT_MESSAGE
|
||||
external_service = trans.sa_session.query( trans.model.ExternalService ).get( trans.security.decode_id( external_service_id ) )
|
||||
external_service.load_data_transfer_settings( trans )
|
||||
scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_protocol.SCP ]
|
||||
cmd = 'ssh %s@%s "ls -oghp \'%s\'"' % ( scp_configs[ 'user_name' ],
|
||||
scp_configs[ 'host' ],
|
||||
folder_path )
|
||||
# Handle the authentication message if ssh keys are not set - the message is
|
||||
# something like: "Are you sure you want to continue connecting (yes/no)."
|
||||
output = pexpect.run( cmd,
|
||||
events={ '\(yes\/no\)\.*' : 'yes\r\n',
|
||||
'.ssword:*' : scp_configs[ 'password' ] + '\r\n',
|
||||
pexpect.TIMEOUT : print_ticks },
|
||||
timeout=10 )
|
||||
for password_str in [ 'Password:\r\n', 'password:\r\n' ]:
|
||||
# Eliminate the output created using ssh from the tree
|
||||
if password_str in output:
|
||||
output = output.replace( password_str, '' )
|
||||
return text_type( output.replace( '\r\n', '<br/>' ) )
|
||||
|
||||
@web.json
|
||||
def open_folder( self, trans, request_id, external_service_id, key ):
|
||||
# Avoid caching
|
||||
trans.response.headers['Pragma'] = 'no-cache'
|
||||
trans.response.headers['Expires'] = '0'
|
||||
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
|
||||
external_service = trans.sa_session.query( trans.model.ExternalService ).get( trans.security.decode_id( external_service_id ) )
|
||||
folder_path = key
|
||||
files_list = self.__get_files( trans, request, external_service, folder_path )
|
||||
folder_contents = []
|
||||
for filename in files_list:
|
||||
is_folder = False
|
||||
if filename and filename[-1] == os.sep:
|
||||
is_folder = True
|
||||
if filename:
|
||||
full_path = os.path.join( folder_path, filename )
|
||||
node = { "title": filename,
|
||||
"isFolder": is_folder,
|
||||
"isLazy": is_folder,
|
||||
"tooltip": full_path,
|
||||
"key": full_path }
|
||||
folder_contents.append( node )
|
||||
return folder_contents
|
||||
|
||||
def __get_files( self, trans, request, external_service, folder_path ):
|
||||
# Retrieves the filenames to be transferred from the remote host.
|
||||
ok = True
|
||||
external_service.load_data_transfer_settings( trans )
|
||||
scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_protocol.SCP ]
|
||||
if not scp_configs[ 'host' ] or not scp_configs[ 'user_name' ] or not scp_configs[ 'password' ]:
|
||||
status = 'error'
|
||||
message = "Error in external service login information."
|
||||
ok = False
|
||||
|
||||
def print_ticks( d ):
|
||||
pass
|
||||
cmd = 'ssh %s@%s "ls -p \'%s\'"' % ( scp_configs[ 'user_name' ], scp_configs[ 'host' ], folder_path )
|
||||
# Handle the authentication message if keys are not set - the message is
|
||||
# something like: "Are you sure you want to continue connecting (yes/no)."
|
||||
if pexpect is not None:
|
||||
output = pexpect.run( cmd,
|
||||
events={ '\(yes\/no\)\.*' : 'yes\r\n',
|
||||
'.ssword:*' : scp_configs[ 'password' ] + '\r\n',
|
||||
pexpect.TIMEOUT : print_ticks },
|
||||
timeout=10 )
|
||||
if 'No such file or directory' in output:
|
||||
status = 'error'
|
||||
message = "No folder named (%s) exists on the external service." % folder_path
|
||||
ok = False
|
||||
else:
|
||||
status = 'error'
|
||||
message = PEXPECT_IMPORT_MESSAGE
|
||||
ok = False
|
||||
if ok:
|
||||
if 'assword:' in output:
|
||||
# Eliminate the output created using ssh from the tree
|
||||
output_as_list = output.splitlines()[ 1: ]
|
||||
else:
|
||||
output_as_list = output.splitlines()
|
||||
return output_as_list
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_admin',
|
||||
action='select_datasets_to_transfer',
|
||||
request_id=trans.security.encode_id( request.id ),
|
||||
external_service_id=trans.security.encode_id( external_service.id ),
|
||||
status=status,
|
||||
message=message ) )
|
||||
|
||||
def __create_sample_datasets( self, trans, sample, selected_datasets_to_transfer, external_service ):
|
||||
external_service.load_data_transfer_settings( trans )
|
||||
scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_protocol.SCP ]
|
||||
sample_dataset_file_names = []
|
||||
if selected_datasets_to_transfer:
|
||||
for filepath in selected_datasets_to_transfer:
|
||||
# FIXME: handle folder selection - ignore folders for now
|
||||
if filepath[-1] != os.sep:
|
||||
name = self.__rename_dataset( sample, filepath.split( '/' )[-1], scp_configs )
|
||||
status = trans.app.model.SampleDataset.transfer_status.NOT_STARTED
|
||||
size = sample.get_untransferred_dataset_size( filepath, scp_configs )
|
||||
sample_dataset = trans.model.SampleDataset( sample=sample,
|
||||
file_path=filepath,
|
||||
status=status,
|
||||
name=name,
|
||||
error_msg='',
|
||||
size=size,
|
||||
external_service=external_service )
|
||||
trans.sa_session.add( sample_dataset )
|
||||
trans.sa_session.flush()
|
||||
sample_dataset_file_names.append( str( sample_dataset.name ) )
|
||||
return sample_dataset_file_names
|
||||
|
||||
def __rename_dataset( self, sample, filepath, scp_configs ):
|
||||
name = filepath.split( '/' )[-1]
|
||||
options = sample.request.type.rename_dataset_options
|
||||
option = scp_configs.get( 'rename_dataset', options.NO )
|
||||
if option == options.SAMPLE_NAME:
|
||||
new_name = sample.name + '_' + name
|
||||
if option == options.EXPERIMENT_AND_SAMPLE_NAME:
|
||||
new_name = sample.request.name + '_' + sample.name + '_' + name
|
||||
if option == options.EXPERIMENT_NAME:
|
||||
new_name = sample.request.name + '_' + name
|
||||
else:
|
||||
new_name = name
|
||||
return util.sanitize_for_filename( new_name )
|
||||
|
||||
def __ensure_library_add_permission( self, trans, target_library, target_folder ):
|
||||
"""
|
||||
Ensures the current admin user has ADD_LIBRARY permission on the target data library and folder.
|
||||
@@ -594,92 +385,6 @@ class RequestsAdmin( BaseUIController, UsesFormDefinitionsMixin ):
|
||||
if flush_needed:
|
||||
trans.sa_session.flush()
|
||||
|
||||
def __create_data_transfer_messages( self, trans, sample, selected_sample_datasets ):
|
||||
"""
|
||||
Creates the xml messages to send to the rabbitmq server. It returns a dictionary of messages
|
||||
keyed by the external service used to transfer the datasets
|
||||
"""
|
||||
# Create the xml message based on the following template
|
||||
xml = \
|
||||
''' <data_transfer>
|
||||
<galaxy_host>%(GALAXY_HOST)s</galaxy_host>
|
||||
<api_key>%(API_KEY)s</api_key>
|
||||
<data_host>%(DATA_HOST)s</data_host>
|
||||
<data_user>%(DATA_USER)s</data_user>
|
||||
<data_password>%(DATA_PASSWORD)s</data_password>
|
||||
<request_id>%(REQUEST_ID)s</request_id>
|
||||
<sample_id>%(SAMPLE_ID)s</sample_id>
|
||||
<library_id>%(LIBRARY_ID)s</library_id>
|
||||
<folder_id>%(FOLDER_ID)s</folder_id>
|
||||
%(DATASETS)s
|
||||
</data_transfer>'''
|
||||
dataset_xml = \
|
||||
'''<dataset>
|
||||
<dataset_id>%(ID)s</dataset_id>
|
||||
<name>%(NAME)s</name>
|
||||
<file>%(FILE)s</file>
|
||||
</dataset>'''
|
||||
# Here we group all the sample_datasets by the external service used to transfer them.
|
||||
# The idea is to bundle up the sample_datasets which uses the same external service and
|
||||
# send a single AMQP message to the galaxy_listener
|
||||
dataset_elements = {}
|
||||
for sample_dataset in selected_sample_datasets:
|
||||
external_service = sample_dataset.external_service
|
||||
if sample_dataset.status == trans.app.model.SampleDataset.transfer_status.NOT_STARTED:
|
||||
if external_service not in dataset_elements:
|
||||
dataset_elements[ external_service ] = ''
|
||||
dataset_elements[ external_service ] += dataset_xml % dict( ID=str( sample_dataset.id ),
|
||||
NAME=sample_dataset.name,
|
||||
FILE=sample_dataset.file_path )
|
||||
# update the dataset transfer status
|
||||
sample_dataset.status = trans.app.model.SampleDataset.transfer_status.IN_QUEUE
|
||||
trans.sa_session.add( sample_dataset )
|
||||
trans.sa_session.flush()
|
||||
# Finally prepend the external service info to the sets of sample datasets
|
||||
messages = []
|
||||
for external_service, dataset_elem in dataset_elements.items():
|
||||
external_service.load_data_transfer_settings( trans )
|
||||
scp_configs = external_service.data_transfer[ trans.model.ExternalService.data_transfer_protocol.SCP ]
|
||||
# Check data transfer settings
|
||||
err_msg = self.__validate_data_transfer_settings( trans, sample.request.type, scp_configs )
|
||||
if err_msg:
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_admin',
|
||||
action='manage_datasets',
|
||||
sample_id=trans.security.encode_id( sample.id ),
|
||||
status='error',
|
||||
message=err_msg ) )
|
||||
message = xml % dict( GALAXY_HOST=trans.request.host,
|
||||
API_KEY=trans.user.api_keys[0].key,
|
||||
DATA_HOST=scp_configs[ 'host' ],
|
||||
DATA_USER=scp_configs[ 'user_name' ],
|
||||
DATA_PASSWORD=scp_configs[ 'password' ],
|
||||
REQUEST_ID=str( sample.request.id ),
|
||||
SAMPLE_ID=str( sample.id ),
|
||||
LIBRARY_ID=str( sample.library.id ),
|
||||
FOLDER_ID=str( sample.folder.id ),
|
||||
DATASETS=dataset_elem )
|
||||
messages.append( message.replace( '\n', '' ).replace( '\r', '' ) )
|
||||
return messages
|
||||
|
||||
def __validate_data_transfer_settings( self, trans, request_type, scp_configs ):
|
||||
err_msg = ''
|
||||
# check the external service login info
|
||||
if not scp_configs.get( 'host', '' ) or \
|
||||
not scp_configs.get( 'user_name', '' ) or \
|
||||
not scp_configs.get( 'password', '' ):
|
||||
err_msg += "Error in external service login information. "
|
||||
if not trans.user.api_keys:
|
||||
err_msg += "Set your API Key in your User Preferences to transfer datasets. "
|
||||
# Check if library_import_dir is set
|
||||
if not trans.app.config.library_import_dir:
|
||||
err_msg = "'The library_import_dir' setting is not correctly set in the Galaxy config file. "
|
||||
# Check the RabbitMQ server settings in the config file
|
||||
for k, v in trans.app.config.amqp.items():
|
||||
if not v:
|
||||
err_msg += 'Set RabbitMQ server settings in the "galaxy_amqp" section of the Galaxy config file, specifically "%s" is not set.' % k
|
||||
break
|
||||
return err_msg
|
||||
|
||||
@web.expose
|
||||
@web.require_admin
|
||||
def initiate_data_transfer( self, trans, sample_id, sample_datasets=[], sample_dataset_id='' ):
|
||||
@@ -721,35 +426,8 @@ class RequestsAdmin( BaseUIController, UsesFormDefinitionsMixin ):
|
||||
external_service=external_service,
|
||||
external_service_type=external_service_type )
|
||||
else:
|
||||
# TODO: Using RabbitMq for now, but eliminate this entire block when we replace RabbitMq with Galaxy's
|
||||
# own messaging engine. We're holding off on using the new way to transfer files manually until we
|
||||
# implement a Galaxy-proprietary messaging engine because the deferred job plugins currently perform
|
||||
# constant db hits to check for deferred jobs that are not in a finished state.
|
||||
# Create the message
|
||||
messages = self.__create_data_transfer_messages( trans, sample, sample_datasets )
|
||||
# Send the messages
|
||||
for rmq_msg in messages:
|
||||
try:
|
||||
conn = amqp.Connection( host=trans.app.config.amqp[ 'host' ] + ":" + trans.app.config.amqp[ 'port' ],
|
||||
userid=trans.app.config.amqp[ 'userid' ],
|
||||
password=trans.app.config.amqp[ 'password' ],
|
||||
virtual_host=trans.app.config.amqp[ 'virtual_host' ])
|
||||
chan = conn.channel()
|
||||
msg = amqp.Message( rmq_msg,
|
||||
content_type='text/plain',
|
||||
application_headers={ 'msg_type': 'data_transfer' } )
|
||||
msg.properties[ "delivery_mode" ] = 2
|
||||
chan.basic_publish( msg,
|
||||
exchange=trans.app.config.amqp[ 'exchange' ],
|
||||
routing_key=trans.app.config.amqp[ 'routing_key' ] )
|
||||
chan.close()
|
||||
conn.close()
|
||||
except Exception, e:
|
||||
message = "Error sending the data transfer message to the Galaxy AMQP message queue:<br/>%s" % str(e)
|
||||
status = "error"
|
||||
if not message:
|
||||
message = "%i datasets have been queued for transfer from the external service." % len( sample_datasets )
|
||||
status = "done"
|
||||
message = "Message queue transfer is no longer supported, please set enable_beta_job_managers = True in galaxy.ini"
|
||||
status = "error"
|
||||
return trans.response.send_redirect( web.url_for( controller='requests_admin',
|
||||
action='manage_datasets',
|
||||
sample_id=trans.security.encode_id( sample.id ),
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace file="/message.mako" import="render_msg" />
|
||||
<%namespace file="/requests/common/common.mako" import="render_sample_datasets" />
|
||||
<%namespace file="/requests/common/common.mako" import="common_javascripts" />
|
||||
|
||||
<%def name="javascripts()">
|
||||
${parent.javascripts()}
|
||||
${common_javascripts()}
|
||||
</%def>
|
||||
|
||||
${h.js( "libs/jquery/jquery-ui", "libs/jquery/jquery.cookie", "libs/jquery/jquery.dynatree" )}
|
||||
${h.css( "dynatree_skin/ui.dynatree" )}
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$("#tree").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) {
|
||||
_log("debug", "ajaxComplete: %o", this); // dom element listening
|
||||
});
|
||||
// --- Initialize sample trees
|
||||
$("#tree").dynatree({
|
||||
title: "${scp_configs['data_location']}",
|
||||
minExpandLevel: 1, // 1: root node is not collapsible
|
||||
persist: false,
|
||||
checkbox: true,
|
||||
selectMode: 3,
|
||||
onPostInit: function(isReloading, isError) {
|
||||
//alert("reloading: "+isReloading+", error:"+isError);
|
||||
logMsg("onPostInit(%o, %o) - %o", isReloading, isError, this);
|
||||
// Re-fire onActivate, so the text is updated
|
||||
this.reactivate();
|
||||
},
|
||||
fx: { height: "toggle", duration: 200 },
|
||||
// initAjax is hard to fake, so we pass the children as object array:
|
||||
initAjax: {url: "${h.url_for( controller='requests_admin', action='open_folder' )}",
|
||||
dataType: "json",
|
||||
data: { request_id: "${trans.security.encode_id( request.id )}", external_service_id: "${trans.security.encode_id( external_service.id )}", key: "${scp_configs['data_location']}" },
|
||||
},
|
||||
onLazyRead: function(dtnode){
|
||||
dtnode.appendAjax({
|
||||
url: "${h.url_for( controller='requests_admin', action='open_folder' )}",
|
||||
dataType: "json",
|
||||
data: { request_id: "${trans.security.encode_id( request.id )}", external_service_id: "${trans.security.encode_id( external_service.id )}", key: dtnode.data.key },
|
||||
});
|
||||
},
|
||||
onSelect: function(select, dtnode) {
|
||||
// Display list of selected nodes
|
||||
var selNodes = dtnode.tree.getSelectedNodes();
|
||||
// convert to title/key array
|
||||
var selKeys = $.map(selNodes, function(node){
|
||||
return node.data.key;
|
||||
});
|
||||
document.select_datasets_to_transfer.selected_datasets_to_transfer.value = selKeys.join(",")
|
||||
},
|
||||
onActivate: function(dtnode) {
|
||||
var cell = $("#file_details");
|
||||
var selected_value;
|
||||
if (dtnode.data.key == 'root') {
|
||||
selected_value = "${scp_configs['data_location']}/";
|
||||
} else {
|
||||
selected_value = dtnode.data.key;
|
||||
};
|
||||
if (selected_value.charAt(selected_value.length-1) != '/') {
|
||||
// Make ajax call
|
||||
$.ajax( {
|
||||
type: "POST",
|
||||
url: "${h.url_for( controller='requests_admin', action='get_file_details' )}",
|
||||
dataType: "json",
|
||||
data: { request_id: "${trans.security.encode_id(request.id)}", external_service_id: "${trans.security.encode_id(external_service.id)}", folder_path: selected_value },
|
||||
success : function ( data ) {
|
||||
cell.html( '<label>'+data+'</label>' )
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cell.html( '' );
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%
|
||||
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
|
||||
can_transfer_datasets = is_admin and sample.untransferred_dataset_files and sample.library and sample.folder
|
||||
%>
|
||||
|
||||
<br/><br/>
|
||||
<ul class="manage-table-actions">
|
||||
<li><a class="action-button" href="${h.url_for( controller='external_service', action='view_external_service', id=trans.security.encode_id( external_service.id ) )}">External service configuration</a></li>
|
||||
%if can_transfer_datasets:
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Transfer datasets</a></li>
|
||||
%endif
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a></li>
|
||||
</ul>
|
||||
|
||||
%if not sample:
|
||||
<br/>
|
||||
<font color="red"><b><i>Select a sample before selecting datasets to transfer</i></b></font>
|
||||
<br/>
|
||||
%endif
|
||||
|
||||
%if request.samples_without_library_destinations:
|
||||
<p>
|
||||
<font color="red"><b><i>Select a target data library and folder for a sample before selecting its datasets to transfer from the external service</i></b></font>
|
||||
</p>
|
||||
%endif
|
||||
|
||||
%if message:
|
||||
${render_msg( message, status )}
|
||||
%endif
|
||||
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">Select datasets to transfer from data directory configured for the external service</div>
|
||||
<form name="select_datasets_to_transfer" id="select_datasets_to_transfer" action="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, external_service_id=trans.security.encode_id( external_service.id ), request_id=trans.security.encode_id( request.id ))}" method="post" >
|
||||
<div class="form-row">
|
||||
<label>Sample:</label>
|
||||
${sample_id_select_field.get_html()}
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
Select the sample that was sequenced to produce the datasets you want to transfer.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" >
|
||||
<label>Select datasets from source data location defined in the external service configuration:</label>
|
||||
<div id="tree" >
|
||||
Loading...
|
||||
</div>
|
||||
<input id="selected_datasets_to_transfer" name="selected_datasets_to_transfer" type="hidden" size=40"/>
|
||||
<div class="toolParamHelp" style="clear: both;">
|
||||
<ul>
|
||||
<li>Click the <b>external service configuration</b> button and change the <b>Data directory</b> setting to redefine the source data location.</li>
|
||||
<li>Select a folder to select all of the individual files within that folder.</li>
|
||||
<li>Click the <b>Select datasets</b> button when desired dataset check boxes are checked.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div id="file_details" class="toolParamHelp" style="clear: both;background-color:#FAFAFA;"></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="submit" name="select_datasets_to_transfer_button" value="Select datasets"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
%if sample and sample.datasets:
|
||||
<% title = 'All selected datasets for "%s"' % sample.name %>
|
||||
<p/>
|
||||
${render_sample_datasets( 'requests_admin', sample, sample.datasets, title )}
|
||||
%endif
|
||||
@@ -333,7 +333,6 @@
|
||||
can_add_samples = is_unsubmitted
|
||||
can_delete_samples = not adding_new_samples and request.samples and ( ( is_admin and not is_complete ) or is_unsubmitted )
|
||||
can_edit_samples = request.samples and ( is_admin or not is_complete )
|
||||
can_select_datasets = is_admin and displayable_sample_widgets and ( is_submitted or is_complete )
|
||||
can_transfer_datasets = is_admin and request.samples and not request.is_rejected
|
||||
display_checkboxes = not adding_new_samples and ( is_complete or is_rejected or is_submitted )
|
||||
display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
|
||||
@@ -407,7 +406,7 @@
|
||||
%elif sample:
|
||||
<tr>
|
||||
<td>
|
||||
%if sample.state and ( can_select_datasets or can_transfer_datasets ):
|
||||
%if sample.state and can_transfer_datasets:
|
||||
## A sample will have a state only after the request has been submitted.
|
||||
<%
|
||||
encoded_id = trans.security.encode_id( sample.id )
|
||||
@@ -419,14 +418,6 @@
|
||||
<a class="view-info" href="${h.url_for( controller='requests_common', action='view_sample', cntrller=cntrller, id=trans.security.encode_id( sample.id ) )}">${sample.name | h}</a>
|
||||
</div>
|
||||
<div popupmenu="sample-${sample.id}-popup">
|
||||
%if can_select_datasets:
|
||||
%for external_service in sample.request.type.get_external_services_for_manual_data_transfer( trans ):
|
||||
<%
|
||||
menu_item_label = "Select datasets to transfer using %s" % external_service.name
|
||||
%>
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', external_service_id=trans.security.encode_id( external_service.id ), request_id=trans.security.encode_id( request.id ), sample_id=trans.security.encode_id( sample.id ) )}">${menu_item_label}</a></li>
|
||||
%endfor
|
||||
%endif
|
||||
%if sample.datasets and len( sample.datasets ) > len( transferred_dataset_files ) and sample.library and sample.folder:
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', sample_id=trans.security.encode_id( sample.id ) )}">Manage selected datasets</a></li>
|
||||
%elif sample.datasets and len( sample.datasets ) == len( transferred_dataset_files ):
|
||||
@@ -665,7 +656,6 @@
|
||||
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
|
||||
is_complete = sample.request.is_complete
|
||||
is_submitted = sample.request.is_submitted
|
||||
can_select_datasets = is_admin and ( is_complete or is_submitted )
|
||||
can_transfer_datasets = is_admin and sample.untransferred_dataset_files
|
||||
%>
|
||||
## The transfer status should update only when the request has been submitted or complete
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
can_add_samples = is_unsubmitted
|
||||
can_edit_request = ( is_admin and not is_complete ) or is_unsubmitted
|
||||
can_reject = is_admin and is_submitted
|
||||
can_select_datasets = is_admin and ( is_complete or is_submitted )
|
||||
can_submit_request = request.samples and is_unsubmitted
|
||||
%>
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
|
||||
is_complete = sample.request.is_complete
|
||||
is_submitted = sample.request.is_submitted
|
||||
can_select_datasets = is_admin and ( is_complete or is_submitted )
|
||||
can_transfer_datasets = is_admin and sample.untransferred_dataset_files and sample.library and sample.folder
|
||||
%>
|
||||
|
||||
@@ -24,9 +23,6 @@
|
||||
%endif
|
||||
<li><a class="action-button" id="sample-${sample.id}-popup" class="menubutton">Dataset Actions</a></li>
|
||||
<div popupmenu="sample-${sample.id}-popup">
|
||||
%if can_select_datasets:
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, external_service_id=trans.security.encode_id( external_service.id ), request_id=trans.security.encode_id( sample.request.id ), sample_id=trans.security.encode_id( sample.id ) )}">Select more datasets</a></li>
|
||||
%endif
|
||||
<li><a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( sample.library.id ) )}">View target Data Library</a></li>
|
||||
<li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user