diff --git a/lib/galaxy/interfaces/proxy.py b/lib/galaxy/interfaces/proxy.py index f713c70ee0f..575659b38be 100644 --- a/lib/galaxy/interfaces/proxy.py +++ b/lib/galaxy/interfaces/proxy.py @@ -80,7 +80,7 @@ class UCSCProxy(common.Root): else: try: text = page.read() - + # Serialize store into a form element store_text = "" diff --git a/lib/galaxy/interfaces/root.py b/lib/galaxy/interfaces/root.py index 35aa19eaaf1..18f394b684b 100644 --- a/lib/galaxy/interfaces/root.py +++ b/lib/galaxy/interfaces/root.py @@ -27,6 +27,8 @@ class Universe(common.Root): trans.set_cookie(name=self.pref_cookie_name, value=mode) else: mode = trans.get_cookie(name=self.pref_cookie_name) + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() result = trans.fill_template('index_frames.tmpl', mode=mode) return [ result ] @@ -319,6 +321,13 @@ class Universe(common.Root): new_history = self.copy_history(history) new_history.name = history.name+" from "+user.email new_history.user_id = send_to_user.id + """ + gvk TODO: how should we handle galaxy_session_to_history association here? + I'll do the following for now, but not sure if this is what we want... + """ + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() + new_history.add_galaxy_session(trans.get_galaxy_session()) trans.log_event( "History share: %s to %s" % (str(history.id),str(new_history.id)) ) self.app.model.flush() return trans.show_message( "History (%s) has been shared with: %s" % (",".join(history_names),email) ) @@ -333,6 +342,8 @@ class Universe(common.Root): @web.expose def history_import( self, trans, id=None, confirm=False, **kwd ): + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() msg = "" user = trans.get_user() user_history = trans.get_history() @@ -347,6 +358,7 @@ class Universe(common.Root): new_history = self.copy_history(import_history) new_history.name = "imported: "+new_history.name new_history.user_id = user.id + new_history.add_galaxy_session(trans.get_galaxy_session()) new_history.flush() if not user_history.datasets: trans.set_history( new_history ) @@ -356,6 +368,7 @@ class Universe(common.Root): new_history = self.copy_history(import_history) new_history.name = "imported: "+new_history.name new_history.user_id = None + new_history.add_galaxy_session(trans.get_galaxy_session()) new_history.flush() trans.set_history( new_history ) trans.log_event( "History import: %s" % str(new_history.id) ) @@ -367,8 +380,11 @@ class Universe(common.Root): if not id: return trans.fill_template( "history_switch.tmpl" ) else: + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() new_history = trans.app.model.History.get( id ) if new_history: + new_history.add_galaxy_session(trans.get_galaxy_session()) trans.set_history( new_history ) trans.log_event( "History switch" ) return trans.show_message( "History switched to: %s" % new_history.name, @@ -379,7 +395,7 @@ class Universe(common.Root): @web.expose def history_new( self, trans ): trans.new_history() - trans.log_event( "History new" ) + trans.log_event( "Created new History." ) return self.history( trans ) @web.expose diff --git a/lib/galaxy/interfaces/tool_runner.py b/lib/galaxy/interfaces/tool_runner.py index b93238ed4b5..82e1e45f716 100644 --- a/lib/galaxy/interfaces/tool_runner.py +++ b/lib/galaxy/interfaces/tool_runner.py @@ -37,6 +37,8 @@ class ToolRunner(common.Root): return "Tool '%s' does not exist, kwd=%s " % (tool_id, kwd) params = util.Params(kwd) history = trans.get_history() + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() template, vars = tool.handle_input( trans, params.__dict__ ) - trans.log_event( "Tool View: %s; %s" % (str(tool),str(params)) ) + trans.log_event( "Tool View: %s; %s" % (str(tool),str(params)), tool_id=tool_id ) return trans.fill_template( template, history=history, toolbox=toolbox, tool=tool, util=util, **vars ) \ No newline at end of file diff --git a/lib/galaxy/interfaces/user.py b/lib/galaxy/interfaces/user.py index d3effbe404f..fc9b65070cd 100644 --- a/lib/galaxy/interfaces/user.py +++ b/lib/galaxy/interfaces/user.py @@ -88,6 +88,13 @@ class User( common.Root ): password_error = "Invalid password" else: trans.set_user( user ) + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() + else: + """ + Associate user with galaxy_session and history + """ + trans.make_associations() trans.log_event( "User logged in" ) return trans.show_ok_message( "Now logged in as " + user.email, \ refresh_frames=['masthead', 'history'] ) @@ -98,12 +105,12 @@ class User( common.Root ): @web.expose def logout( self, trans ): - # If the current history is saved for the current user it should be - # disconnected. + trans.log_event( "User logged out" ) + # If the current history is saved for the current user it should be disconnected. if trans.history.user == trans.user: trans.set_history( None ) - trans.log_event( "User logged out" ) trans.set_user( None ) + trans.end_galaxy_session() return trans.show_ok_message( "You are no longer logged in", \ refresh_frames=['masthead', 'history'] ) @@ -126,7 +133,14 @@ class User( common.Root ): user.set_password_cleartext( password ) user.flush() trans.set_user( user ) - trans.log_event( "User new" ) + if not trans.galaxy_session_is_valid(): + trans.new_galaxy_session() + else: + """ + Associate user with galaxy_session and history + """ + trans.make_associations() + trans.log_event( "User created a new account" ) trans.log_event( "User logged in" ) #subscribe user to email list if subscribe: diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py index d5d7924dd80..5f549794bd4 100644 --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -209,6 +209,10 @@ class JobWrapper( object ): def get_command_line( self ): job = model.Job.get( self.job_id ) return job.command_line + + def get_session_id( self ): + job = model.Job.get( self.job_id ) + return job.session_id def get_input_fnames( self ): job = model.Job.get( self.job_id ) diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 2953f5e7a0b..d1504973606 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -37,6 +37,7 @@ class Job( object ): OK = 'ok', ERROR = 'error' ) def __init__( self ): + self.session_id = None self.tool_id = None self.command_line = None self.param_filename = None @@ -79,6 +80,7 @@ class History( object ): # Relationships self.user = user self.datasets = [] + self.galaxy_sessions = [] def _next_hid( self ): # TODO: override this with something in the database that ensures @@ -91,6 +93,9 @@ class History( object ): if dataset.hid > last_hid: last_hid = dataset.hid return last_hid + 1 + + def add_galaxy_session( self, galaxy_session ): + self.galaxy_sessions.append( GalaxySessionToHistoryAssociation( galaxy_session, self ) ) def add_dataset( self, dataset, parent_id=None ): if parent_id: @@ -98,6 +103,7 @@ class History( object ): if data.id == parent_id: dataset.hid = data.hid break + # TODO gvk: ask if this needs to be fixed, I don't want to break it if it isn't broken... else: dataset.hid = self._next_hid() else: @@ -250,7 +256,27 @@ class Dataset( object ): log.critical('%s delete error %s' % (self.__class__.__name__, e)) class Event( object ): - def __init__( self, message=None, history=None, user=None ): - self.message = message + def __init__( self, message=None, history=None, user=None, galaxy_session=None ): self.history = history + self.galaxy_session = galaxy_session self.user = user + self.tool_id = None + self.message = message + +class GalaxySession( object ): + def __init__( self, id=None, user=None, remote_host=None, remote_addr=None ): + self.id = id + self.user = user + self.remote_host = remote_host + self.remote_addr = remote_addr + self.histories = [] + + def add_history( self, history ): + self.histories.append( GalaxySessionToHistoryAssociation( self, history ) ) + +class GalaxySessionToHistoryAssociation( object ): + def __init__( self, galaxy_session, history ): + self.galaxy_session = galaxy_session + self.history = history + + diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py index 410f8bbb30c..79a8ccca4ee 100644 --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -73,6 +73,7 @@ Job.table = Table( "job", metadata, Column( "id", Integer, primary_key=True ), Column( "create_time", DateTime, PassiveDefault( func.current_timestamp() ) ), Column( "update_time", DateTime, PassiveDefault( func.current_timestamp() ), onupdate=func.current_timestamp() ), + Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), nullable=True ), Column( "history_id", Integer, ForeignKey( "history.id" ) ), Column( "tool_id", String( 255 ) ), Column( "state", String( 64 ) ), @@ -104,10 +105,26 @@ Event.table = Table( "event", metadata, Column( "id", Integer, primary_key=True ), Column( "create_time", DateTime, PassiveDefault( func.current_timestamp() ) ), Column( "update_time", DateTime, PassiveDefault( func.current_timestamp() ), onupdate=func.current_timestamp() ), - Column( "history_id", Integer, nullable=True ), + Column( "history_id", Integer, ForeignKey( "history.id" ), nullable=True ), + Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), nullable=True ), Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), nullable=True ), + Column( "tool_id", String( 255 ) ), Column( "message", TrimmedString( 1024 ) ) ) +GalaxySession.table = Table( "galaxy_session", metadata, + Column( "id", Integer, primary_key=True ), + Column( "create_time", DateTime, PassiveDefault( func.current_timestamp() ) ), + Column( "update_time", DateTime, PassiveDefault( func.current_timestamp() ), onupdate=func.current_timestamp() ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), nullable=True ), + Column( "remote_host", String( 255 ) ), + Column( "remote_addr", String( 255 ) ) ) + +GalaxySessionToHistoryAssociation.table = Table( "galaxy_session_to_history", metadata, + Column( "id", Integer, primary_key=True ), + Column( "create_time", DateTime, PassiveDefault( func.current_timestamp() ) ), + Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ) ), + Column( "history_id", Integer, ForeignKey( "history.id" ) ) ) + # With the tables defined we can define the mappers and setup the # relationships between the model objects. @@ -119,7 +136,8 @@ assign_mapper( context, Dataset, Dataset.table, # properties=dict( datasets=relation( model.Dataset.mapper, backref="query") ) ) assign_mapper( context, History, History.table, - properties=dict( datasets=relation( Dataset, backref="history", order_by=asc(Dataset.table.c.hid) ), + properties=dict( galaxy_sessions=relation( GalaxySessionToHistoryAssociation ), + datasets=relation( Dataset, backref="history", order_by=asc(Dataset.table.c.hid) ), active_datasets=relation( Dataset, primaryjoin=( ( Dataset.c.history_id == History.table.c.id ) & ( Dataset.c.deleted == False ) ), order_by=asc( Dataset.table.c.hid ), lazy=False, viewonly=True ) ) ) assign_mapper( context, User, User.table, @@ -135,13 +153,24 @@ assign_mapper( context, JobToOutputDatasetAssociation, JobToOutputDatasetAssocia assign_mapper( context, JobParameter, JobParameter.table ) assign_mapper( context, Job, Job.table, - properties=dict( history=relation( History ), + properties=dict( galaxy_session=relation( GalaxySession ), + history=relation( History ), parameters=relation( JobParameter ), input_datasets=relation( JobToInputDatasetAssociation ), output_datasets=relation( JobToOutputDatasetAssociation ) ) ) assign_mapper( context, Event, Event.table, - properties=dict( user=relation( User.mapper ) ) ) + properties=dict( history=relation( History ), + galaxy_session=relation( GalaxySession ), + user=relation( User.mapper ) ) ) + +assign_mapper( context, GalaxySession, GalaxySession.table, + properties=dict( histories=relation( GalaxySessionToHistoryAssociation ), + user=relation( User.mapper ) ) ) + +assign_mapper( context, GalaxySessionToHistoryAssociation, GalaxySessionToHistoryAssociation.table, + properties=dict( galaxy_session=relation( GalaxySession ), + history=relation( History ) ) ) def db_next_hid( self ): """ diff --git a/lib/galaxy/model/mapping_tests.py b/lib/galaxy/model/mapping_tests.py index c6ed148d237..e5d2729d476 100644 --- a/lib/galaxy/model/mapping_tests.py +++ b/lib/galaxy/model/mapping_tests.py @@ -8,6 +8,7 @@ class MappingTests( unittest.TestCase ): assert model.engine is not None # Make some changes and commit them u = model.User( email="james@foo.bar.baz", password="password" ) + # gs = model.GalaxySession() h1 = model.History( name="History 1", user=u) #h1.queries.append( model.Query( "h1->q1" ) ) #h1.queries.append( model.Query( "h1->q2" ) ) @@ -39,6 +40,7 @@ class MappingTests( unittest.TestCase ): hists = model.History.select() assert hists[0].name == "History 1" assert hists[1].name == "History 2b" + # gvk TODO need to ad test for GalaxySessions, but not yet sure what they should look like. def get_suite(): suite = unittest.TestSuite() diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py index 8226d79da73..b95282348d8 100644 --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -588,6 +588,14 @@ class DefaultToolAction( object ): # Create the job object job = trans.app.model.Job() + if trans.galaxy_session_is_valid(): + a_galaxy_session = trans.get_galaxy_session() + else: + a_galaxy_session = trans.new_galaxy_session() + job.session_id = a_galaxy_session.id + a_history = trans.get_history() + if a_history is not None: + job.history_id = a_history.id job.tool_id = tool.id job.command_line = command_line job.param_filename = param_filename diff --git a/lib/galaxy/tools/actions/upload.py b/lib/galaxy/tools/actions/upload.py index 40b610e0889..4b9a6e45f81 100644 --- a/lib/galaxy/tools/actions/upload.py +++ b/lib/galaxy/tools/actions/upload.py @@ -7,7 +7,6 @@ class UploadToolAction( object ): Action for uploading files """ def execute( self, tool, trans, incoming={} ): - data_file = incoming['file_data'] file_type = incoming['file_type'] dbkey = incoming['dbkey'] diff --git a/lib/galaxy/web/__init__.py b/lib/galaxy/web/__init__.py index 12954c7abbd..95cf6de6946 100644 --- a/lib/galaxy/web/__init__.py +++ b/lib/galaxy/web/__init__.py @@ -24,21 +24,24 @@ NOT_SET = object() class UniverseWebTransaction( framework.DefaultWebTransaction ): """ Encapsulates web transaction specific state for the Universe application - (specifically the user's history) + (specifically the user's "cookie" session and history) """ def __init__( self, environ, app ): self.app = app self.__user = NOT_SET self.__history = NOT_SET + self.__galaxy_session = NOT_SET framework.DefaultWebTransaction.__init__( self, environ ) self.app.model.context.current.clear() self.debug = asbool( self.app.config.get( 'debug', False ) ) - def log_event( self, message, **kwargs ): + + def log_event( self, message, tool_id=None, **kwargs ): """ Application level logging. Still needs fleshing out (log levels and such) """ event = self.app.model.Event() + event.tool_id = tool_id try: event.message = message % kwargs except: @@ -49,7 +52,10 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): except: event.history_id = None event.user = self.user + if self.galaxy_session_is_valid(): + event.session_id = self.galaxy_session.id event.flush() + def get_cookie( self, name='universe' ): """ Convienience method for getting the universe cookie @@ -63,6 +69,7 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): return self.request.cookies[name].value except Exception: return None + def set_cookie( self, value, name='universe', path='/', age=90, version='1' ): """ Convienience method for setting the universe cookie @@ -73,6 +80,7 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): tstamp = time.localtime ( time.time() + 3600 * 24 * age ) self.response.cookies[name]['expires'] = time.strftime('%a, %d-%b-%Y %H:%M:%S GMT', tstamp) self.response.cookies[name]['version'] = version + def get_history( self ): """ Load the current history @@ -84,14 +92,20 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): history = self.app.model.History.get( id ) if history is None: history = self.new_history() - self.__history = history - return self.__history + self.__history = history + return self.__history + def new_history( self ): history = self.app.model.History() + if history.user_id is None and self.user is not None: + history.user_id = self.user.id + if self.galaxy_session_is_valid(): + history.add_galaxy_session(self.get_galaxy_session()) history.flush() self.set_cookie( name='universe', value=history.id ) self.__history = history return history + def set_history( self, history ): if history is None: self.set_cookie( name='universe', value='' ) @@ -99,6 +113,7 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): self.set_cookie( name='universe', value=history.id ) self.__history = history history = property( get_history, set_history ) + def get_user( self ): """ Return the current user if logged in (based on cookie) or `None`. @@ -110,6 +125,7 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): else: self.__user = self.app.model.User.get( int( id ) ) return self.__user + def set_user( self, user ): """ Set the current user to `user` (by setting a cookie). @@ -119,7 +135,75 @@ class UniverseWebTransaction( framework.DefaultWebTransaction ): else: self.set_cookie( name='universe_user', value=user.id ) self.__user = user - user = property( get_user, set_user ) + user = property( get_user, set_user ) + + def get_galaxy_session( self ): + """ + Return the current user's galaxy_session. + """ + if self.__galaxy_session is NOT_SET: + id = self.get_cookie( name='universe_session' ) + if not id: + self.__galaxy_session = None + else: + self.__galaxy_session = self.app.model.GalaxySession.get( int( id ) ) + return self.__galaxy_session + + def new_galaxy_session( self ): + galaxy_session = self.app.model.GalaxySession() + if self.user is not None: + galaxy_session.user_id = self.user.id + galaxy_session.remote_host = self.request.remote_host + galaxy_session.remote_addr = self.request.remote_addr + if self.history is not None: + galaxy_session.add_history(self.history) + galaxy_session.flush() + self.set_cookie( name='universe_session', value=galaxy_session.id ) + self.__galaxy_session = galaxy_session + return self.__galaxy_session + + def set_galaxy_session( self, galaxy_session ): + """ + Set the current galaxy_session by setting the universe_session cookie. + """ + if galaxy_session is None: + #TODO we may want to raise an exception here instead of creating a new galaxy_session + galaxy_session = self.new_galaxy_session() + else: + if galaxy_session.user_id is None and self.user is not None: + galaxy_session.user_id = self.user.id + galaxy_session.flush() + self.set_cookie( name='universe_session', value=galaxy_session.id ) + self.__galaxy_session = galaxy_session + + def galaxy_session_is_valid( self ): + # TODO do we want better validation here? + valid = False + a_galaxy_session = self.get_galaxy_session() + if a_galaxy_session is not None and a_galaxy_session.id is not None: + valid = True + return valid + + def end_galaxy_session( self ): + """ + End the current galaxy_session by expiring the universe_session cookie. + """ + if self.galaxy_session_is_valid(): + self.set_cookie( name='universe_session', value=self.galaxy_session.id, age=0 ) + self.__galaxy_session = None + galaxy_session = property( get_galaxy_session, set_galaxy_session ) + + def make_associations( self ): + if self.galaxy_session_is_valid(): + if self.galaxy_session.user_id is None and self.user is not None: + self.galaxy_session.user_id = self.user.id + self.galaxy_session.flush() + self.__galaxy_session = self.galaxy_session + if self.history is not None and self.user is not None: + self.history.user_id = self.user.id + self.history.flush() + self.__history = self.history + def get_toolbox(self): """Returns the application toolbox""" return self.app.toolbox