details: http://www.bx.psu.edu/hg/galaxy/rev/6a65fd82ed3c changeset: 3391:6a65fd82ed3c user: Dan Blankenberg <dan@bx.psu.edu> date: Mon Feb 15 09:10:48 2010 -0500 description: Update display applications to work through the view history (before import) display. diffstat: lib/galaxy/datatypes/display_applications/application.py | 24 ++++++----- lib/galaxy/datatypes/display_applications/helpers.py | 31 --------------- lib/galaxy/datatypes/display_applications/parameters.py | 24 ++++++------ lib/galaxy/datatypes/display_applications/util.py | 32 ++++++++++++++++ lib/galaxy/web/buildapp.py | 2 +- lib/galaxy/web/controllers/dataset.py | 29 ++++++++------ 6 files changed, 75 insertions(+), 67 deletions(-) diffs (305 lines): diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/datatypes/display_applications/application.py --- a/lib/galaxy/datatypes/display_applications/application.py Mon Feb 15 09:02:58 2010 -0500 +++ b/lib/galaxy/datatypes/display_applications/application.py Mon Feb 15 09:10:48 2010 -0500 @@ -5,7 +5,7 @@ from galaxy.web import url_for from parameters import DisplayApplicationParameter, DEFAULT_DATASET_NAME from urllib import quote_plus -from helpers import encode_dataset_user +from util import encode_dataset_user #Any basic functions that we want to provide as a basic part of parameter dict should be added to this dict BASE_PARAMS = { 'qp': quote_plus, 'url_for':url_for } #url_for has route memory... @@ -33,31 +33,33 @@ self.id = None self.name = None def get_display_url( self, data, trans ): - dataset_hash, user_hash = encode_dataset_user( trans, data, trans.user ) - return url_for( controller = 'dataset', action = "display_application", dataset_id = dataset_hash, user_id = user_hash, app_name = self.display_application.id, link_name = self.id, app_action = 'display' ) + dataset_hash, user_hash = encode_dataset_user( trans, data, None ) + return url_for( controller = 'dataset', action = "display_application", dataset_id = dataset_hash, user_id = user_hash, app_name = self.display_application.id, link_name = self.id, app_action = None ) def get_inital_values( self, data, trans ): rval = odict( { 'BASE_URL': trans.request.base, 'APP': trans.app } ) #trans automatically appears as a response, need to add properties of trans that we want here for key, value in BASE_PARAMS.iteritems(): #add helper functions/variables rval[ key ] = value rval[ DEFAULT_DATASET_NAME ] = data #always have the display dataset name available return rval - def build_parameter_dict( self, data, trans ): + def build_parameter_dict( self, data, dataset_hash, user_hash, trans ): other_values = self.get_inital_values( data, trans ) for name, param in self.parameters.iteritems(): assert name not in other_values, "The display parameter '%s' has been defined more than once." % name if param.ready( other_values ): - other_values[ name ] = param.get_value( other_values, trans )#subsequent params can rely on this value + other_values[ name ] = param.get_value( other_values, dataset_hash, user_hash, trans )#subsequent params can rely on this value else: other_values[ name ] = None return False, other_values #need to stop here, next params may need this value return True, other_values #we built other_values, lets provide it as well, or else we will likely regenerate it in the next step class PopulatedDisplayApplicationLink( object ): - def __init__( self, display_application_link, data, trans ): + def __init__( self, display_application_link, data, dataset_hash, user_hash, trans ): self.link = display_application_link self.data = data - self.trans = trans - self.ready, self.parameters = self.link.build_parameter_dict( self.data, trans ) + self.dataset_hash = dataset_hash + self.user_hash = user_hash + self.trans = trans + self.ready, self.parameters = self.link.build_parameter_dict( self.data, self.dataset_hash, self.user_hash, trans ) def display_ready( self ): return self.ready def get_param_value( self, name ): @@ -75,7 +77,7 @@ other_values = self.parameters for name, param in self.link.parameters.iteritems(): if other_values.keys()[ -1 ] == name: #found last parameter to be populated - value = param.prepare( other_values, self.trans ) + value = param.prepare( other_values, self.dataset_hash, self.user_hash, self.trans ) if value is None: return #we can go no further until we have a value for this parameter other_values[ name ] = value @@ -110,7 +112,7 @@ version = "1.0.0" self.version = version self.links = odict() - def get_link( self, link_name, data, trans ): + def get_link( self, link_name, data, dataset_hash, user_hash, trans ): #returns a link object with data knowledge to generate links - return PopulatedDisplayApplicationLink( self.links[ link_name ], data, trans ) + return PopulatedDisplayApplicationLink( self.links[ link_name ], data, dataset_hash, user_hash, trans ) diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/datatypes/display_applications/helpers.py --- a/lib/galaxy/datatypes/display_applications/helpers.py Mon Feb 15 09:02:58 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -import pkg_resources -pkg_resources.require( "pycrypto" ) -from Crypto.Cipher import Blowfish - -def encode_dataset_user( trans, dataset, user ): - #encode dataset id as usual - #encode user id using the dataset create time as the key - dataset_hash = trans.security.encode_id( dataset.id ) - if user is None: - user_id = 'None' - else: - user_id = str( user.id ) - # Pad to a multiple of 8 with leading "!" - user_id = ( "!" * ( 8 - len( user_id ) % 8 ) ) + user_id - cipher = Blowfish.new( str( dataset.create_time ) ) - return dataset_hash, cipher.encrypt( user_id ).encode( 'hex' ) - -def decode_dataset_user( trans, dataset_hash, user_hash ): - #decode dataset id as usual - #decode user id using the dataset create time as the key - dataset_id = trans.security.decode_id( dataset_hash ) - dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dataset_id ) - assert dataset, "Bad Dataset id provided to decode_dataset_user" - cipher = Blowfish.new( str( dataset.create_time ) ) - user_id = cipher.decrypt( user_hash.decode( 'hex' ) ).lstrip( "!" ) - if user_id =='None': - user = None - else: - user = trans.sa_session.query( trans.app.model.User ).get( int( user_id ) ) - assert user, "A Bad user id was passed to decode_dataset_user" - return dataset, user diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/datatypes/display_applications/parameters.py --- a/lib/galaxy/datatypes/display_applications/parameters.py Mon Feb 15 09:02:58 2010 -0500 +++ b/lib/galaxy/datatypes/display_applications/parameters.py Mon Feb 15 09:10:48 2010 -0500 @@ -1,5 +1,4 @@ #Contains parameters that are used in Display Applications -from helpers import encode_dataset_user from galaxy.util import string_as_bool from galaxy.util.bunch import Bunch from galaxy.util.template import fill_template @@ -28,10 +27,10 @@ self.viewable = string_as_bool( elem.get( 'viewable', 'False' ) ) #only allow these to be viewed via direct url when explicitly set to viewable self.strip = string_as_bool( elem.get( 'strip', 'False' ) ) self.strip_https = string_as_bool( elem.get( 'strip_https', 'False' ) ) - def get_value( self, other_values, trans ): + def get_value( self, other_values, dataset_hash, user_hash, trans ): raise Exception, 'Unimplemented' - def prepare( self, other_values, trans ): - return self.get_value( other_values, trans ) + def prepare( self, other_values, dataset_hash, user_hash, trans ): + return self.get_value( other_values, dataset_hash, user_hash, trans ) def ready( self, other_values ): return True def is_preparing( self, other_values ): @@ -76,12 +75,12 @@ assert data.find_conversion_destination( self.formats )[0] is not None, "No conversion path found for data param: %s" % self.name return None return data - def get_value( self, other_values, trans ): + def get_value( self, other_values, dataset_hash, user_hash, trans ): data = self._get_dataset_like_object( other_values ) if data: - return DisplayDataValueWrapper( data, self, other_values, trans ) + return DisplayDataValueWrapper( data, self, other_values, dataset_hash, user_hash, trans ) return None - def prepare( self, other_values, trans ): + def prepare( self, other_values, dataset_hash, user_hash, trans ): data = self._get_dataset_like_object( other_values ) if not data and self.formats: data = other_values.get( self.dataset, None ) @@ -102,7 +101,7 @@ trans.sa_session.flush() elif converted_dataset and converted_dataset.state == converted_dataset.states.ERROR: raise Exception, "Dataset conversion failed for data parameter: %s" % self.name - return self.get_value( other_values, trans ) + return self.get_value( other_values, dataset_hash, user_hash, trans ) def is_preparing( self, other_values ): value = self._get_dataset_like_object( other_values ) if value and value.state in ( value.states.NEW, value.states.UPLOAD, value.states.QUEUED, value.states.RUNNING ): @@ -125,22 +124,23 @@ def __init__( self, elem, link ): DisplayApplicationParameter.__init__( self, elem, link ) self.text = elem.text - def get_value( self, other_values, trans ): + def get_value( self, other_values, dataset_hash, user_hash, trans ): value = fill_template( self.text, context = other_values ) if self.strip: value = value.strip() - return DisplayParameterValueWrapper( value, self, other_values, trans ) + return DisplayParameterValueWrapper( value, self, other_values, dataset_hash, user_hash, trans ) parameter_type_to_class = { DisplayApplicationDataParameter.type:DisplayApplicationDataParameter, DisplayApplicationTemplateParameter.type:DisplayApplicationTemplateParameter } class DisplayParameterValueWrapper( object ): ACTION_NAME = 'param' - def __init__( self, value, parameter, other_values, trans ): + def __init__( self, value, parameter, other_values, dataset_hash, user_hash, trans ): self.value = value self.parameter = parameter self.other_values = other_values self.trans = trans - self._dataset_hash, self._user_hash = encode_dataset_user( trans, self.other_values[ DEFAULT_DATASET_NAME ], self.other_values[ DEFAULT_DATASET_NAME ].history.user ) + self._dataset_hash = dataset_hash + self._user_hash = user_hash def __str__( self ): return str( self.value ) def mime_type( self ): diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/datatypes/display_applications/util.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/datatypes/display_applications/util.py Mon Feb 15 09:10:48 2010 -0500 @@ -0,0 +1,32 @@ +import pkg_resources +pkg_resources.require( "pycrypto" ) +from Crypto.Cipher import Blowfish + +def encode_dataset_user( trans, dataset, user ): + #encode dataset id as usual + #encode user id using the dataset create time as the key + dataset_hash = trans.security.encode_id( dataset.id ) + if user is None: + user_hash = 'None' + else: + user_hash = str( user.id ) + # Pad to a multiple of 8 with leading "!" + user_hash = ( "!" * ( 8 - len( user_hash ) % 8 ) ) + user_hash + cipher = Blowfish.new( str( dataset.create_time ) ) + user_hash = cipher.encrypt( user_hash ).encode( 'hex' ) + return dataset_hash, user_hash + +def decode_dataset_user( trans, dataset_hash, user_hash ): + #decode dataset id as usual + #decode user id using the dataset create time as the key + dataset_id = trans.security.decode_id( dataset_hash ) + dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dataset_id ) + assert dataset, "Bad Dataset id provided to decode_dataset_user" + if user_hash in [ None, 'None' ]: + user = None + else: + cipher = Blowfish.new( str( dataset.create_time ) ) + user_id = cipher.decrypt( user_hash.decode( 'hex' ) ).lstrip( "!" ) + user = trans.sa_session.query( trans.app.model.User ).get( int( user_id ) ) + assert user, "A Bad user id was passed to decode_dataset_user" + return dataset, user diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/web/buildapp.py --- a/lib/galaxy/web/buildapp.py Mon Feb 15 09:02:58 2010 -0500 +++ b/lib/galaxy/web/buildapp.py Mon Feb 15 09:10:48 2010 -0500 @@ -74,7 +74,7 @@ webapp.add_route( '/:controller/:action', action='index' ) webapp.add_route( '/:action', controller='root', action='index' ) webapp.add_route( '/datasets/:dataset_id/:action/:filename', controller='dataset', action='index', dataset_id=None, filename=None) - webapp.add_route( '/display_application/:dataset_id/:user_id/:app_name/:link_name/:app_action/:action_param', controller='dataset', action='display_application', dataset_id=None, user_id=None, app_name = None, link_name = None, app_action = None, action_param = None ) + webapp.add_route( '/display_application/:dataset_id/:app_name/:link_name/:user_id/:app_action/:action_param', controller='dataset', action='display_application', dataset_id=None, user_id=None, app_name = None, link_name = None, app_action = None, action_param = None ) webapp.add_route( '/u/:username/d/:slug', controller='dataset', action='display_by_username_and_slug' ) webapp.add_route( '/u/:username/p/:slug', controller='page', action='display_by_username_and_slug' ) webapp.add_route( '/u/:username/h/:slug', controller='history', action='display_by_username_and_slug' ) diff -r 7e5797d6b584 -r 6a65fd82ed3c lib/galaxy/web/controllers/dataset.py --- a/lib/galaxy/web/controllers/dataset.py Mon Feb 15 09:02:58 2010 -0500 +++ b/lib/galaxy/web/controllers/dataset.py Mon Feb 15 09:10:48 2010 -0500 @@ -4,7 +4,7 @@ from galaxy.web.framework.helpers import time_ago, iff, grids from galaxy import util, datatypes, jobs, web, model from cgi import escape, FieldStorage -from galaxy.datatypes.display_applications.helpers import decode_dataset_user +from galaxy.datatypes.display_applications.util import encode_dataset_user, decode_dataset_user from email.MIMEText import MIMEText @@ -357,12 +357,16 @@ return trans.show_error_message( "You are not allowed to view this dataset at external sites. Please contact your Galaxy administrator to acquire management permissions for this dataset." ) @web.expose - def display_application( self, trans, dataset_id=None, user_id=None, app_name = None, link_name = None, app_action = None, action_param = None ): + def display_application( self, trans, dataset_id=None, user_id=None, app_name = None, link_name = None, app_action = None, action_param = None, **kwds ): """Access to external display applications""" + if kwds: + log.debug( "Unexpected Keywords passed to display_application: %s" % kwds ) #route memory? #decode ids data, user = decode_dataset_user( trans, dataset_id, user_id ) if not data: raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) ) + if user is None: + user = trans.user if user: user_roles = user.all_roles() else: @@ -370,15 +374,13 @@ if None in [ app_name, link_name ]: return trans.show_error_message( "A display application name and link name must be provided." ) - if app_action is None: - app_action = "display" # default action is display - if trans.app.security_agent.can_access_dataset( user_roles, data.dataset ): msg = [] refresh = False display_app = trans.app.datatypes_registry.display_applications.get( app_name ) assert display_app, "Unknown display application has been requested: %s" % app_name - display_link = display_app.get_link( link_name, data, trans ) + dataset_hash, user_hash = encode_dataset_user( trans, data, user ) + display_link = display_app.get_link( link_name, data, dataset_hash, user_hash, trans ) assert display_link, "Unknown display link has been requested: %s" % link_name if data.state == data.states.ERROR: msg.append( ( 'This dataset is in an error state, you cannot view it at an external display application.', 'error' ) ) @@ -409,16 +411,19 @@ trans.response.set_content_type( value.mime_type() ) trans.response.headers[ 'Content-Length' ] = content_length return rval - elif app_action == "display": + elif app_action == None: return trans.fill_template_mako( "dataset/display_application/launch_display.mako", display_link = display_link ) else: msg.append( ( 'Invalid action provided: %s' % app_action, 'error' ) ) else: - msg.append( ( 'This display application is being prepared.', 'info' ) ) - if app_action == "display": - refresh = True - if not display_link.preparing_display(): - display_link.prepare_display() + if app_action == None: + if trans.history != data.history: + msg.append( ( 'You must import this dataset into your current history before you can view it at the desired display application.', 'error' ) ) + else: + refresh = True + msg.append( ( 'This display application is being prepared.', 'info' ) ) + if not display_link.preparing_display(): + display_link.prepare_display() else: raise Exception( 'Attempted a view action (%s) on a non-ready display application' % app_action ) return trans.fill_template_mako( "dataset/display_application/display.mako", msg = msg, display_app = display_app, display_link = display_link, refresh = refresh )