HDA & History Managers: move serialization logic for bootstrapping into view, display_by_username_and_slug, and root/history into Managers in order to display dataset collections

This commit is contained in:
Carl Eberhard
2014-07-10 09:56:17 -04:00
parent 16cad94834
commit 3cae3f3922
7 changed files with 731 additions and 418 deletions
+32 -3
View File
@@ -1,4 +1,33 @@
""" 'Business logic' independent of web transactions/user context (trans)
should be pushed into models - but logic that requires the context trans
should be placed under this module.
"""
Classes that manage resources (models, tools, etc.) by using the current
Transaction.
Encapsulates the intersection of trans (or trans.sa_session), models,
and Controllers.
Responsibilities:
model operations that involve the trans/sa_session (CRUD)
security:
ownership, accessibility
common aspect-oriented operations via new mixins:
sharable, annotatable, tagable, ratable
Not responsible for:
encoding/decoding ids
any http gobblygook
formatting of returned data (always python structures)
formatting of raised errors
The goal is to have Controllers only handle:
query-string/payload parsing and encoding/decoding ids
http
return formatting
and:
control, improve namespacing in Controllers
DRY for Controller ops (define here - use in both UI/API Controllers)
In other words, 'Business logic' independent of web transactions/user context
(trans) should be pushed into models - but logic that requires the context
trans should be placed under this module.
"""
+7
View File
@@ -0,0 +1,7 @@
class ModelManager( object ):
pass
class ModelSerializer( object ):
pass
+179 -5
View File
@@ -1,16 +1,35 @@
"""
Manager and Serializer for HDAs.
HistoryDatasetAssociations (HDAs) are datasets contained or created in a
history.
"""
from galaxy import exceptions
from ..managers import histories
from galaxy.managers import base as manager_base
from galaxy.managers import histories as history_manager
class HDAManager( object ):
import galaxy.web
import galaxy.datatypes.metadata
from galaxy import objectstore
class HDAManager( manager_base.ModelManager ):
"""
Interface/service object for interacting with HDAs.
"""
def __init__( self ):
self.histories_mgr = histories.HistoryManager()
"""
Set up and initialize other managers needed by hdas.
"""
self.histories_mgr = history_manager.HistoryManager()
def get( self, trans, unencoded_id, check_ownership=True, check_accessible=True ):
"""
Get an HDA by its unencoded db id, checking ownership (via its history)
or accessibility (via dataset shares/permissions).
"""
# this is a replacement for UsesHistoryDatasetAssociationMixin because mixins are a bad soln/structure
hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( unencoded_id )
if hda is None:
raise exceptions.ObjectNotFound()
@@ -19,7 +38,8 @@ class HDAManager( object ):
def secure( self, trans, hda, check_ownership=True, check_accessible=True ):
"""
checks if (a) user owns item or (b) item is accessible to user.
check ownership (via its history) or accessibility (via dataset
shares/permissions).
"""
# all items are accessible to an admin
if trans.user and trans.user_is_admin():
@@ -31,12 +51,18 @@ class HDAManager( object ):
return hda
def can_access_dataset( self, trans, hda ):
"""
Use security agent to see if current user has access to dataset.
"""
current_user_roles = trans.get_current_user_roles()
return trans.app.security_agent.can_access_dataset( current_user_roles, hda.dataset )
#TODO: is_owner, is_accessible
def check_ownership( self, trans, hda ):
"""
Use history to see if current user owns HDA.
"""
if not trans.user:
#if hda.history == trans.history:
# return hda
@@ -51,6 +77,9 @@ class HDAManager( object ):
"HistoryDatasetAssociation is not owned by the current user", type='error' )
def check_accessible( self, trans, hda ):
"""
Raise error if HDA is not accessible.
"""
if trans.user and trans.user_is_admin():
return hda
# check for access of the containing history...
@@ -62,6 +91,151 @@ class HDAManager( object ):
"HistoryDatasetAssociation is not accessible to the current user", type='error' )
def err_if_uploading( self, trans, hda ):
"""
Raise error if HDA is still uploading.
"""
if hda.state == trans.model.Dataset.states.UPLOAD:
raise exceptions.Conflict( "Please wait until this dataset finishes uploading" )
return hda
def get_hda_dict( self, trans, hda ):
"""
Return full details of this HDA in dictionary form.
"""
#precondition: the user's access to this hda has already been checked
#TODO:?? postcondition: all ids are encoded (is this really what we want at this level?)
expose_dataset_path = trans.user_is_admin() or trans.app.config.expose_dataset_path
hda_dict = hda.to_dict( view='element', expose_dataset_path=expose_dataset_path )
hda_dict[ 'api_type' ] = "file"
# Add additional attributes that depend on trans must be added here rather than at the model level.
can_access_hda = trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset )
can_access_hda = ( trans.user_is_admin() or can_access_hda )
if not can_access_hda:
return self.get_inaccessible_hda_dict( trans, hda )
hda_dict[ 'accessible' ] = True
#TODO: I'm unclear as to which access pattern is right
hda_dict[ 'annotation' ] = hda.get_item_annotation_str( trans.sa_session, hda.history.user, hda )
#annotation = getattr( hda, 'annotation', hda.get_item_annotation_str( trans.sa_session, trans.user, hda ) )
# ---- return here if deleted AND purged OR can't access
purged = ( hda.purged or hda.dataset.purged )
if ( hda.deleted and purged ):
#TODO: to_dict should really go AFTER this - only summary data
return trans.security.encode_dict_ids( hda_dict )
if expose_dataset_path:
try:
hda_dict[ 'file_name' ] = hda.file_name
except objectstore.ObjectNotFound:
log.exception( 'objectstore.ObjectNotFound, HDA %s.', hda.id )
hda_dict[ 'download_url' ] = galaxy.web.url_for( 'history_contents_display',
history_id = trans.security.encode_id( hda.history.id ),
history_content_id = trans.security.encode_id( hda.id ) )
# indeces, assoc. metadata files, etc.
meta_files = []
for meta_type in hda.metadata.spec.keys():
if isinstance( hda.metadata.spec[ meta_type ].param, galaxy.datatypes.metadata.FileParameter ):
meta_files.append( dict( file_type=meta_type ) )
if meta_files:
hda_dict[ 'meta_files' ] = meta_files
# currently, the viz reg is optional - handle on/off
if trans.app.visualizations_registry:
hda_dict[ 'visualizations' ] = trans.app.visualizations_registry.get_visualizations( trans, hda )
else:
hda_dict[ 'visualizations' ] = hda.get_visualizations()
#TODO: it may also be wiser to remove from here and add as API call that loads the visualizations
# when the visualizations button is clicked (instead of preloading/pre-checking)
# ---- return here if deleted
if hda.deleted and not purged:
return trans.security.encode_dict_ids( hda_dict )
return trans.security.encode_dict_ids( hda_dict )
def get_inaccessible_hda_dict( self, trans, hda ):
"""
Return truncated serialization of HDA when inaccessible to user.
"""
return trans.security.encode_dict_ids({
'id' : hda.id,
'history_id': hda.history.id,
'hid' : hda.hid,
'name' : hda.name,
'state' : hda.state,
'deleted' : hda.deleted,
'visible' : hda.visible,
'accessible': False
})
def get_hda_dict_with_error( self, trans, hda=None, history_id=None, id=None, error_msg='Error' ):
"""
Return truncated serialization of HDA when error raised getting
details.
"""
return trans.security.encode_dict_ids({
'id' : hda.id if hda else id,
'history_id': hda.history.id if hda else history_id,
'hid' : hda.hid if hda else '(unknown)',
'name' : hda.name if hda else '(unknown)',
'error' : error_msg,
'state' : trans.model.Dataset.states.NEW
})
def get_display_apps( self, trans, hda ):
"""
Return dictionary containing new-style display app urls.
"""
display_apps = []
for display_app in hda.get_display_applications( trans ).itervalues():
app_links = []
for link_app in display_app.links.itervalues():
app_links.append({
'target': link_app.url.get( 'target_frame', '_blank' ),
'href' : link_app.get_display_url( hda, trans ),
'text' : gettext( link_app.name )
})
if app_links:
display_apps.append( dict( label=display_app.name, links=app_links ) )
return display_apps
def get_old_display_applications( self, trans, hda ):
"""
Return dictionary containing old-style display app urls.
"""
display_apps = []
if not trans.app.config.enable_old_display_applications:
return display_apps
for display_app in hda.datatype.get_display_types():
target_frame, display_links = hda.datatype.get_display_links( hda,
display_app, trans.app, trans.request.base )
if len( display_links ) > 0:
display_label = hda.datatype.get_display_label( display_app )
app_links = []
for display_name, display_link in display_links:
app_links.append({
'target': target_frame,
'href' : display_link,
'text' : gettext( display_name )
})
if app_links:
display_apps.append( dict( label=display_label, links=app_links ) )
return display_apps
# =============================================================================
class HistorySerializer( manager_base.ModelSerializer ):
"""
Interface/service object for serializing HDAs into dictionaries.
"""
pass
+138 -2
View File
@@ -1,9 +1,32 @@
"""
Manager and Serializer for histories.
Histories are containers for datasets or dataset collections
created (or copied) by users over the course of an analysis.
"""
from galaxy import exceptions
from galaxy.model import orm
from galaxy.managers import base as manager_base
import galaxy.managers.hdas
import galaxy.web
import galaxy.dataset_collections.util
import logging
log = logging.getLogger( __name__ )
# =============================================================================
class HistoryManager( manager_base.ModelManager ):
"""
Interface/service object for interacting with HDAs.
"""
class HistoryManager( object ):
#TODO: all the following would be more useful if passed the user instead of defaulting to trans.user
def __init__( self, *args, **kwargs ):
super( HistoryManager, self ).__init__( *args, **kwargs )
def get( self, trans, unencoded_id, check_ownership=True, check_accessible=True, deleted=None ):
"""
@@ -44,7 +67,7 @@ class HistoryManager( object ):
def secure( self, trans, history, check_ownership=True, check_accessible=True ):
"""
checks if (a) user owns item or (b) item is accessible to user.
Checks if (a) user owns item or (b) item is accessible to user.
"""
# all items are accessible to an admin
if trans.user and trans.user_is_admin():
@@ -56,15 +79,28 @@ class HistoryManager( object ):
return history
def is_current( self, trans, history ):
"""
True if the given history is the user's current history.
Returns False if the session has no current history.
"""
if trans.history is None:
return False
return trans.history == history
def is_owner( self, trans, history ):
"""
True if the current user is the owner of the given history.
"""
# anon users are only allowed to view their current history
if not trans.user:
return self.is_current( trans, history )
return trans.user == history.user
def check_ownership( self, trans, history ):
"""
Raises error if the current user is not the owner of the history.
"""
if trans.user and trans.user_is_admin():
return history
if not trans.user and not self.is_current( trans, history ):
@@ -74,6 +110,9 @@ class HistoryManager( object ):
raise exceptions.ItemOwnershipException( "History is not owned by the current user", type='error' )
def is_accessible( self, trans, history ):
"""
True if the user can access (read) the current history.
"""
# admin always have access
if trans.user and trans.user_is_admin():
return True
@@ -88,6 +127,103 @@ class HistoryManager( object ):
return False
def check_accessible( self, trans, history ):
"""
Raises error if the current user can't access the history.
"""
if self.is_accessible( trans, history ):
return history
raise exceptions.ItemAccessibilityException( "History is not accessible to the current user", type='error' )
#TODO: bleh...
def _get_history_data( self, trans, history ):
"""
Returns a dictionary containing ``history`` and ``contents``, serialized
history and an array of serialized history contents respectively.
"""
hda_mgr = galaxy.managers.hdas.HDAManager()
collection_dictifier = galaxy.dataset_collections.util.dictify_dataset_collection_instance
history_dictionary = {}
contents_dictionaries = []
try:
#for content in history.contents_iter( **contents_kwds ):
for content in history.contents_iter( types=[ 'dataset', 'dataset_collection' ] ):
hda_dict = {}
if isinstance( content, trans.app.model.HistoryDatasetAssociation ):
try:
hda_dict = hda_mgr.get_hda_dict( trans, content )
except Exception, exc:
# don't fail entire list if hda err's, record and move on
log.exception( 'Error bootstrapping hda: %s', exc )
hda_dict = hda_mgr.get_hda_dict_with_error( trans, content, str( exc ) )
elif isinstance( content, trans.app.model.HistoryDatasetCollectionAssociation ):
try:
service = trans.app.dataset_collections_service
dataset_collection_instance = service.get_dataset_collection_instance(
trans=trans,
instance_type='history',
id=trans.security.encode_id( content.id ),
)
hda_dict = collection_dictifier( dataset_collection_instance,
security=trans.security, parent=dataset_collection_instance.history, view="element" )
except Exception, exc:
log.exception( "Error in history API at listing dataset collection: %s", exc )
#TODO: return some dict with the error
contents_dictionaries.append( hda_dict )
# re-use the hdas above to get the history data...
history_dictionary = self.get_history_dict( trans, history, contents_dictionaries=contents_dictionaries )
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
message = ( 'An error occurred getting the history data from the server. '
+ 'Please contact a Galaxy administrator if the problem persists.' )
history_dictionary[ 'error' ] = message
return {
'history' : history_dictionary,
'contents' : contents_dictionaries
}
def get_history_dict( self, trans, history, contents_dictionaries=None ):
"""
Returns history data in the form of a dictionary.
"""
#TODO: to serializer
history_dict = history.to_dict( view='element', value_mapper={ 'id':trans.security.encode_id })
history_dict[ 'user_id' ] = None
if history.user_id:
history_dict[ 'user_id' ] = trans.security.encode_id( history.user_id )
history_dict[ 'nice_size' ] = history.get_disk_size( nice_size=True )
history_dict[ 'annotation' ] = history.get_item_annotation_str( trans.sa_session, history.user, history )
if not history_dict[ 'annotation' ]:
history_dict[ 'annotation' ] = ''
#TODO: item_slug url
if history_dict[ 'importable' ] and history_dict[ 'slug' ]:
username_and_slug = ( '/' ).join(( 'u', history.user.username, 'h', history_dict[ 'slug' ] ))
history_dict[ 'username_and_slug' ] = username_and_slug
#TODO: re-add
#hda_summaries = hda_dictionaries if hda_dictionaries else self.get_hda_summary_dicts( trans, history )
##TODO remove the following in v2
#( state_counts, state_ids ) = self._get_hda_state_summaries( trans, hda_summaries )
#history_dict[ 'state_details' ] = state_counts
#history_dict[ 'state_ids' ] = state_ids
#history_dict[ 'state' ] = self._get_history_state_from_hdas( trans, history, state_counts )
return history_dict
# =============================================================================
class HistorySerializer( manager_base.ModelSerializer ):
"""
Interface/service object for serializing histories into dictionaries.
"""
pass
@@ -92,7 +92,7 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
else:
types = [ 'dataset', "dataset_collection" ]
contents_kwds = {'types': types}
contents_kwds = { 'types': types }
if ids:
ids = map( lambda id: trans.security.decode_id( id ), ids.split( ',' ) )
contents_kwds[ 'ids' ] = ids
@@ -110,14 +110,14 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
details = util.listify( details )
for content in history.contents_iter( **contents_kwds ):
if isinstance(content, trans.app.model.HistoryDatasetAssociation):
if isinstance( content, trans.app.model.HistoryDatasetAssociation ):
encoded_content_id = trans.security.encode_id( content.id )
detailed = details == 'all' or ( encoded_content_id in details )
if detailed:
rval.append( self._detailed_hda_dict( trans, content ) )
else:
rval.append( self._summary_hda_dict( trans, history_id, content ) )
elif isinstance(content, trans.app.model.HistoryDatasetCollectionAssociation):
elif isinstance( content, trans.app.model.HistoryDatasetCollectionAssociation ):
rval.append( self.__collection_dict( trans, content ) )
return rval
@@ -149,7 +149,8 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
}
def __collection_dict( self, trans, dataset_collection_instance, view="collection" ):
return dictify_dataset_collection_instance( dataset_collection_instance, security=trans.security, parent=dataset_collection_instance.history, view=view )
return dictify_dataset_collection_instance( dataset_collection_instance,
security=trans.security, parent=dataset_collection_instance.history, view=view )
def _detailed_hda_dict( self, trans, hda ):
"""
@@ -201,8 +202,7 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
)
return self.__collection_dict( trans, dataset_collection_instance, view="element" )
except Exception, e:
msg = "Error in history API at listing dataset collection: %s" % ( str(e) )
log.error( msg, exc_info=True )
log.exception( "Error in history API at listing dataset collection: %s", e )
trans.response.status = 500
return msg
+353 -359
View File
@@ -4,6 +4,7 @@ from cgi import escape
import galaxy.util
from galaxy import model
from galaxy import web
from galaxy import managers
from galaxy.datatypes.data import nice_size
from galaxy.model.item_attrs import UsesAnnotations, UsesItemRatings
from galaxy.model.orm import and_, eagerload_all, func
@@ -194,6 +195,12 @@ class HistoryAllPublishedGrid( grids.Grid ):
class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesItemRatings,
UsesHistoryMixin, UsesHistoryDatasetAssociationMixin, ExportsHistoryMixin,
ImportsHistoryMixin ):
def __init__( self, app ):
super( HistoryController, self ).__init__( app )
self.mgrs = util.bunch.Bunch(
histories=managers.histories.HistoryManager()
)
@web.expose
def index( self, trans ):
return ""
@@ -204,6 +211,7 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
trans.response.set_content_type( 'text/xml' )
return trans.fill_template( "/history/list_as_xml.mako" )
# ......................................................................... lists
stored_list_grid = HistoryListGrid()
shared_list_grid = SharedHistoryListGrid()
published_list_grid = HistoryAllPublishedGrid()
@@ -437,6 +445,7 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
# Render the list view
return self.shared_list_grid( trans, status=status, message=message, **kwargs )
# ......................................................................... html
@web.expose
def display_structured( self, trans, id=None ):
"""
@@ -511,333 +520,6 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
#
return trans.fill_template( "history/display_structured.mako", items=items, history=history )
@web.expose
def delete_hidden_datasets( self, trans ):
"""
This method deletes all hidden datasets in the current history.
"""
count = 0
for hda in trans.history.datasets:
if not hda.visible and not hda.deleted and not hda.purged:
hda.mark_deleted()
count += 1
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been deleted" % hda.id )
trans.sa_session.flush()
return trans.show_ok_message( "%d hidden datasets have been deleted" % count, refresh_frames=['history'] )
@web.expose
def purge_deleted_datasets( self, trans ):
count = 0
if trans.app.config.allow_user_dataset_purge:
for hda in trans.history.datasets:
if not hda.deleted or hda.purged:
continue
if trans.user:
trans.user.total_disk_usage -= hda.quota_amount( trans.user )
hda.purged = True
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been purged" % hda.id )
trans.sa_session.flush()
if hda.dataset.user_can_purge:
try:
hda.dataset.full_delete()
trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) )
trans.sa_session.add( hda.dataset )
except:
log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) )
count += 1
return trans.show_ok_message( "%d datasets have been deleted permanently" % count, refresh_frames=['history'] )
#TODO: use api instead
@web.expose
def delete_current( self, trans, purge=False ):
"""Delete just the active history -- this does not require a logged in user."""
history = trans.get_history()
if history.users_shared_with:
return trans.show_error_message( "History (%s) has been shared with others, unshare it before deleting it. " % history.name )
if not history.deleted:
history.deleted = True
trans.sa_session.add( history )
trans.sa_session.flush()
trans.log_event( "History id %d marked as deleted" % history.id )
if purge and trans.app.config.allow_user_dataset_purge:
for hda in history.datasets:
if trans.user:
trans.user.total_disk_usage -= hda.quota_amount( trans.user )
hda.purged = True
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been purged" % hda.id )
trans.sa_session.flush()
if hda.dataset.user_can_purge:
try:
hda.dataset.full_delete()
trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) )
trans.sa_session.add( hda.dataset )
except:
log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) )
history.purged = True
self.sa_session.add( history )
self.sa_session.flush()
for hda in history.datasets:
# Not all datasets have jobs associated with them (e.g., datasets imported from libraries).
if hda.creating_job_associations:
# HDA has associated job, so try marking it deleted.
job = hda.creating_job_associations[0].job
if job.history_id == history.id and job.state in [ trans.app.model.Job.states.QUEUED, trans.app.model.Job.states.RUNNING, trans.app.model.Job.states.NEW ]:
# No need to check other outputs since the job's parent history is this history
job.mark_deleted( trans.app.config.track_jobs_in_database )
trans.app.job_manager.job_stop_queue.put( job.id )
# Regardless of whether it was previously deleted, get or create default history.
trans.get_or_create_default_history()
return trans.show_ok_message( "History deleted, a new history is active", refresh_frames=['history'] )
@web.expose
def unhide_datasets( self, trans, current=False, ids=None ):
"""Unhide the datasets in the active history -- this does not require a logged in user."""
if not ids and galaxy.util.string_as_bool( current ):
histories = [ trans.get_history() ]
refresh_frames = ['history']
else:
raise NotImplementedError( "You can currently only unhide all the datasets of the current history." )
for history in histories:
history.unhide_datasets()
trans.sa_session.add( history )
trans.sa_session.flush()
return trans.show_ok_message( "Your datasets have been unhidden.", refresh_frames=refresh_frames )
#TODO: used in index.mako
@web.expose
def resume_paused_jobs( self, trans, current=False, ids=None ):
"""Resume paused jobs the active history -- this does not require a logged in user."""
if not ids and galaxy.util.string_as_bool( current ):
histories = [ trans.get_history() ]
refresh_frames = ['history']
else:
raise NotImplementedError( "You can currently only resume all the datasets of the current history." )
for history in histories:
history.resume_paused_jobs()
trans.sa_session.add( history )
trans.sa_session.flush()
return trans.show_ok_message( "Your jobs have been resumed.", refresh_frames=refresh_frames )
#TODO: used in index.mako
@web.expose
@web.require_login( "rate items" )
@web.json
def rate_async( self, trans, id, rating ):
""" Rate a history asynchronously and return updated community data. """
history = self.get_history( trans, id, check_ownership=False, check_accessible=True )
if not history:
return trans.show_error_message( "The specified history does not exist." )
# Rate history.
history_rating = self.rate_item( trans.sa_session, trans.get_user(), history, rating )
return self.get_ave_item_rating_data( trans.sa_session, history )
#TODO: used in display_base.mako
@web.expose
# TODO: Remove require_login when users are warned that, if they are not
# logged in, this will remove their current history.
@web.require_login( "use Galaxy histories" )
def import_archive( self, trans, **kwargs ):
""" Import a history from a file archive. """
# Set archive source and type.
archive_file = kwargs.get( 'archive_file', None )
archive_url = kwargs.get( 'archive_url', None )
archive_source = None
if archive_file:
archive_source = archive_file
archive_type = 'file'
elif archive_url:
archive_source = archive_url
archive_type = 'url'
# If no source to create archive from, show form to upload archive or specify URL.
if not archive_source:
return trans.show_form(
web.FormBuilder( web.url_for(controller='history', action='import_archive'), "Import a History from an Archive", submit_text="Submit" ) \
.add_input( "text", "Archived History URL", "archive_url", value="", error=None )
# TODO: add support for importing via a file.
#.add_input( "file", "Archived History File", "archive_file", value=None, error=None )
)
self.queue_history_import( trans, archive_type=archive_type, archive_source=archive_source )
return trans.show_message( "Importing history from '%s'. \
This history will be visible when the import is complete" % archive_source )
#TODO: used in this file and index.mako
@web.expose
def export_archive( self, trans, id=None, gzip=True, include_hidden=False, include_deleted=False ):
""" Export a history to an archive. """
#
# Get history to export.
#
if id:
history = self.get_history( trans, id, check_ownership=False, check_accessible=True )
else:
# Use current history.
history = trans.history
id = trans.security.encode_id( history.id )
if not history:
return trans.show_error_message( "This history does not exist or you cannot export this history." )
#
# If history has already been exported and it has not changed since export, stream it.
#
jeha = history.latest_export
if jeha and jeha.up_to_date:
if jeha.ready:
return self.serve_ready_history_export( trans, jeha )
elif jeha.preparing:
return trans.show_message( "Still exporting history %(n)s; please check back soon. Link: <a href='%(s)s'>%(s)s</a>" \
% ( { 'n' : history.name, 's' : url_for( controller='history', action="export_archive", id=id, qualified=True ) } ) )
self.queue_history_export( trans, history, gzip=gzip, include_hidden=include_hidden, include_deleted=include_deleted )
url = url_for( controller='history', action="export_archive", id=id, qualified=True )
return trans.show_message( "Exporting History '%(n)s'. Use this link to download \
the archive or import it to another Galaxy server: \
<a href='%(u)s'>%(u)s</a>" % ( { 'n' : history.name, 'u' : url } ) )
#TODO: used in this file and index.mako
@web.expose
@web.json
@web.require_login( "get history name and link" )
def get_name_and_link_async( self, trans, id=None ):
""" Returns history's name and link. """
history = self.get_history( trans, id, False )
if self.create_item_slug( trans.sa_session, history ):
trans.sa_session.flush()
return_dict = {
"name" : history.name,
"link" : url_for(controller='history', action="display_by_username_and_slug",
username=history.user.username, slug=history.slug ) }
return return_dict
#TODO: used in page/editor.mako
@web.expose
@web.require_login( "set history's accessible flag" )
def set_accessible_async( self, trans, id=None, accessible=False ):
""" Set history's importable attribute and slug. """
history = self.get_history( trans, id, True )
# Only set if importable value would change; this prevents a change in the update_time unless attribute really changed.
importable = accessible in ['True', 'true', 't', 'T'];
if history and history.importable != importable:
if importable:
self._make_item_accessible( trans.sa_session, history )
else:
history.importable = importable
trans.sa_session.flush()
return
#TODO: used in page/editor.mako
@web.expose
def get_item_content_async( self, trans, id ):
""" Returns item content in HTML format. """
history = self.get_history( trans, id, False, True )
if history is None:
raise web.httpexceptions.HTTPNotFound()
# Get datasets.
datasets = self.get_history_datasets( trans, history )
# Get annotations.
history.annotation = self.get_item_annotation_str( trans.sa_session, history.user, history )
for dataset in datasets:
dataset.annotation = self.get_item_annotation_str( trans.sa_session, history.user, dataset )
return trans.stream_template_mako( "/history/item_content.mako", item = history, item_data = datasets )
#TODO: used in embed_base.mako
@web.expose
def name_autocomplete_data( self, trans, q=None, limit=None, timestamp=None ):
"""Return autocomplete data for history names"""
user = trans.get_user()
if not user:
return
ac_data = ""
for history in ( trans.sa_session.query( model.History )
.filter_by( user=user )
.filter( func.lower( model.History.name ).like(q.lower() + "%") ) ):
ac_data = ac_data + history.name + "\n"
return ac_data
#TODO: used in grid_base.mako
@web.expose
def imp( self, trans, id=None, confirm=False, **kwd ):
"""Import another user's history via a shared URL"""
msg = ""
user = trans.get_user()
user_history = trans.get_history()
# Set referer message
if 'referer' in kwd:
referer = kwd['referer']
else:
referer = trans.request.referer
if referer is not "":
referer_message = "<a href='%s'>return to the previous page</a>" % referer
else:
referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
# include all datasets when copying?
all_datasets = util.string_as_bool( kwd.get( 'all_datasets', False ) )
# Do import.
if not id:
return trans.show_error_message( "You must specify a history you want to import.<br>You can %s." % referer_message, use_panels=True )
import_history = self.get_history( trans, id, check_ownership=False, check_accessible=False )
if not import_history:
return trans.show_error_message( "The specified history does not exist.<br>You can %s." % referer_message, use_panels=True )
# History is importable if user is admin or it's accessible. TODO: probably want to have app setting to enable admin access to histories.
if not trans.user_is_admin() and not self.security_check( trans, import_history, check_ownership=False, check_accessible=True ):
return trans.show_error_message( "You cannot access this history.<br>You can %s." % referer_message, use_panels=True )
if user:
#dan: I can import my own history.
#if import_history.user_id == user.id:
# return trans.show_error_message( "You cannot import your own history.<br>You can %s." % referer_message, use_panels=True )
new_history = import_history.copy( target_user=user, all_datasets=all_datasets )
new_history.name = "imported: " + new_history.name
new_history.user_id = user.id
galaxy_session = trans.get_galaxy_session()
try:
association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \
.filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \
.first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
trans.sa_session.add( new_history )
trans.sa_session.flush()
# Set imported history to be user's current history.
trans.set_history( new_history )
return trans.show_ok_message(
message="""History "%s" has been imported. <br>You can <a href="%s" onclick="parent.window.location='%s';">start using this history</a> or %s."""
% ( new_history.name, web.url_for( '/' ), web.url_for( '/' ), referer_message ), use_panels=True )
elif not user_history or not user_history.datasets or confirm:
#TODO:?? should anon-users be allowed to include deleted datasets when importing?
#new_history = import_history.copy( activatable=include_deleted )
new_history = import_history.copy()
new_history.name = "imported: " + new_history.name
new_history.user_id = None
galaxy_session = trans.get_galaxy_session()
try:
association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \
.filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \
.first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
trans.sa_session.add( new_history )
trans.sa_session.flush()
trans.set_history( new_history )
return trans.show_ok_message(
message="""History "%s" has been imported. <br>You can <a href="%s">start using this history</a> or %s."""
% ( new_history.name, web.url_for( '/' ), referer_message ), use_panels=True )
return trans.show_warn_message( """
Warning! If you import this history, you will lose your current
history. <br>You can <a href="%s">continue and import this history</a> or %s.
""" % ( web.url_for(controller='history', action='imp', id=id, confirm=True, referer=trans.request.referer ), referer_message ), use_panels=True )
#TODO: used in history/view, display, embed
@web.expose
def view( self, trans, id=None, show_deleted=False, show_hidden=False, use_panels=True ):
"""
@@ -870,22 +552,9 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
+ " or the owner of this history has not made it accessible." )
# include all datasets: hidden, deleted, and purged
hdas = self.get_history_datasets( trans, history_to_view,
show_deleted=True, show_hidden=True, show_purged=True )
for hda in hdas:
hda_dict = {}
try:
hda_dict = self.get_hda_dict( trans, hda )
except Exception, exc:
# don't fail entire list if hda err's, record and move on
log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
hda_dict = self.get_hda_dict_with_error( trans, hda, str( exc ) )
hda_dictionaries.append( hda_dict )
# re-use the hdas above to get the history data...
history_dictionary = self.get_history_dict( trans, history_to_view, hda_dictionaries=hda_dictionaries )
history_data = self.mgrs.histories._get_history_data( trans, history_to_view )
history_dictionary = history_data[ 'history' ]
hda_dictionaries = history_data[ 'contents' ]
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
@@ -911,12 +580,6 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
# Security check raises error if user cannot access history.
self.security_check( trans, history, False, True)
# Get datasets and annotations
datasets = self.get_history_datasets( trans, history )
history.annotation = self.get_item_annotation_str( trans.sa_session, history.user, history )
for dataset in datasets:
dataset.annotation = self.get_item_annotation_str( trans.sa_session, history.user, dataset )
# Get rating data.
user_item_rating = 0
if trans.get_user():
@@ -928,20 +591,22 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
ave_item_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, history )
# create ownership flag for template, dictify models
# note: adding original annotation since this is published - get_dict returns user-based annos
user_is_owner = trans.user == history.user
hda_dicts = []
for hda in datasets:
hda_dict = self.get_hda_dict( trans, hda )
hda_dict[ 'annotation' ] = hda.annotation
hda_dicts.append( hda_dict )
history_dict = self.get_history_dict( trans, history, hda_dictionaries=hda_dicts )
history_dict[ 'annotation' ] = history.annotation
history_data = self.mgrs.histories._get_history_data( trans, history )
history_dict = history_data[ 'history' ]
hda_dicts = history_data[ 'contents' ]
return trans.stream_template_mako( "history/display.mako", item=history, item_data=datasets,
history_dict[ 'annotation' ] = self.get_item_annotation_str( trans.sa_session, history.user, history )
# note: adding original annotation since this is published - get_dict returns user-based annos
#for hda_dict in hda_dicts:
# hda_dict[ 'annotation' ] = hda.annotation
# dataset.annotation = self.get_item_annotation_str( trans.sa_session, history.user, dataset )
return trans.stream_template_mako( "history/display.mako", item=history, item_data=[],
user_is_owner=user_is_owner, history_dict=history_dict, hda_dicts=hda_dicts,
user_item_rating = user_item_rating, ave_item_rating=ave_item_rating, num_ratings=num_ratings )
# ......................................................................... sharing & publishing
@web.expose
@web.require_login( "share Galaxy histories" )
def sharing( self, trans, id=None, histories=[], **kwargs ):
@@ -1283,6 +948,334 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
msg += send_to_err
return self.sharing( trans, histories=shared_histories, msg=msg )
# ......................................................................... actions/orig. async
@web.expose
def delete_hidden_datasets( self, trans ):
"""
This method deletes all hidden datasets in the current history.
"""
count = 0
for hda in trans.history.datasets:
if not hda.visible and not hda.deleted and not hda.purged:
hda.mark_deleted()
count += 1
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been deleted" % hda.id )
trans.sa_session.flush()
return trans.show_ok_message( "%d hidden datasets have been deleted" % count, refresh_frames=['history'] )
@web.expose
def purge_deleted_datasets( self, trans ):
count = 0
if trans.app.config.allow_user_dataset_purge:
for hda in trans.history.datasets:
if not hda.deleted or hda.purged:
continue
if trans.user:
trans.user.total_disk_usage -= hda.quota_amount( trans.user )
hda.purged = True
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been purged" % hda.id )
trans.sa_session.flush()
if hda.dataset.user_can_purge:
try:
hda.dataset.full_delete()
trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) )
trans.sa_session.add( hda.dataset )
except:
log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) )
count += 1
return trans.show_ok_message( "%d datasets have been deleted permanently" % count, refresh_frames=['history'] )
#TODO: use api instead
@web.expose
def delete_current( self, trans, purge=False ):
"""Delete just the active history -- this does not require a logged in user."""
history = trans.get_history()
if history.users_shared_with:
return trans.show_error_message( "History (%s) has been shared with others, unshare it before deleting it. " % history.name )
if not history.deleted:
history.deleted = True
trans.sa_session.add( history )
trans.sa_session.flush()
trans.log_event( "History id %d marked as deleted" % history.id )
if purge and trans.app.config.allow_user_dataset_purge:
for hda in history.datasets:
if trans.user:
trans.user.total_disk_usage -= hda.quota_amount( trans.user )
hda.purged = True
trans.sa_session.add( hda )
trans.log_event( "HDA id %s has been purged" % hda.id )
trans.sa_session.flush()
if hda.dataset.user_can_purge:
try:
hda.dataset.full_delete()
trans.log_event( "Dataset id %s has been purged upon the the purge of HDA id %s" % ( hda.dataset.id, hda.id ) )
trans.sa_session.add( hda.dataset )
except:
log.exception( 'Unable to purge dataset (%s) on purge of hda (%s):' % ( hda.dataset.id, hda.id ) )
history.purged = True
self.sa_session.add( history )
self.sa_session.flush()
for hda in history.datasets:
# Not all datasets have jobs associated with them (e.g., datasets imported from libraries).
if hda.creating_job_associations:
# HDA has associated job, so try marking it deleted.
job = hda.creating_job_associations[0].job
if job.history_id == history.id and job.state in [ trans.app.model.Job.states.QUEUED, trans.app.model.Job.states.RUNNING, trans.app.model.Job.states.NEW ]:
# No need to check other outputs since the job's parent history is this history
job.mark_deleted( trans.app.config.track_jobs_in_database )
trans.app.job_manager.job_stop_queue.put( job.id )
# Regardless of whether it was previously deleted, get or create default history.
trans.get_or_create_default_history()
return trans.show_ok_message( "History deleted, a new history is active", refresh_frames=['history'] )
@web.expose
def unhide_datasets( self, trans, current=False, ids=None ):
"""Unhide the datasets in the active history -- this does not require a logged in user."""
if not ids and galaxy.util.string_as_bool( current ):
histories = [ trans.get_history() ]
refresh_frames = ['history']
else:
raise NotImplementedError( "You can currently only unhide all the datasets of the current history." )
for history in histories:
history.unhide_datasets()
trans.sa_session.add( history )
trans.sa_session.flush()
return trans.show_ok_message( "Your datasets have been unhidden.", refresh_frames=refresh_frames )
#TODO: used in index.mako
@web.expose
def resume_paused_jobs( self, trans, current=False, ids=None ):
"""Resume paused jobs the active history -- this does not require a logged in user."""
if not ids and galaxy.util.string_as_bool( current ):
histories = [ trans.get_history() ]
refresh_frames = ['history']
else:
raise NotImplementedError( "You can currently only resume all the datasets of the current history." )
for history in histories:
history.resume_paused_jobs()
trans.sa_session.add( history )
trans.sa_session.flush()
return trans.show_ok_message( "Your jobs have been resumed.", refresh_frames=refresh_frames )
#TODO: used in index.mako
@web.expose
@web.require_login( "rate items" )
@web.json
def rate_async( self, trans, id, rating ):
""" Rate a history asynchronously and return updated community data. """
history = self.get_history( trans, id, check_ownership=False, check_accessible=True )
if not history:
return trans.show_error_message( "The specified history does not exist." )
# Rate history.
history_rating = self.rate_item( trans.sa_session, trans.get_user(), history, rating )
return self.get_ave_item_rating_data( trans.sa_session, history )
#TODO: used in display_base.mako
@web.expose
# TODO: Remove require_login when users are warned that, if they are not
# logged in, this will remove their current history.
@web.require_login( "use Galaxy histories" )
def import_archive( self, trans, **kwargs ):
""" Import a history from a file archive. """
# Set archive source and type.
archive_file = kwargs.get( 'archive_file', None )
archive_url = kwargs.get( 'archive_url', None )
archive_source = None
if archive_file:
archive_source = archive_file
archive_type = 'file'
elif archive_url:
archive_source = archive_url
archive_type = 'url'
# If no source to create archive from, show form to upload archive or specify URL.
if not archive_source:
return trans.show_form(
web.FormBuilder( web.url_for(controller='history', action='import_archive'), "Import a History from an Archive", submit_text="Submit" ) \
.add_input( "text", "Archived History URL", "archive_url", value="", error=None )
# TODO: add support for importing via a file.
#.add_input( "file", "Archived History File", "archive_file", value=None, error=None )
)
self.queue_history_import( trans, archive_type=archive_type, archive_source=archive_source )
return trans.show_message( "Importing history from '%s'. \
This history will be visible when the import is complete" % archive_source )
#TODO: used in this file and index.mako
@web.expose
def export_archive( self, trans, id=None, gzip=True, include_hidden=False, include_deleted=False ):
""" Export a history to an archive. """
#
# Get history to export.
#
if id:
history = self.get_history( trans, id, check_ownership=False, check_accessible=True )
else:
# Use current history.
history = trans.history
id = trans.security.encode_id( history.id )
if not history:
return trans.show_error_message( "This history does not exist or you cannot export this history." )
#
# If history has already been exported and it has not changed since export, stream it.
#
jeha = history.latest_export
if jeha and jeha.up_to_date:
if jeha.ready:
return self.serve_ready_history_export( trans, jeha )
elif jeha.preparing:
return trans.show_message( "Still exporting history %(n)s; please check back soon. Link: <a href='%(s)s'>%(s)s</a>" \
% ( { 'n' : history.name, 's' : url_for( controller='history', action="export_archive", id=id, qualified=True ) } ) )
self.queue_history_export( trans, history, gzip=gzip, include_hidden=include_hidden, include_deleted=include_deleted )
url = url_for( controller='history', action="export_archive", id=id, qualified=True )
return trans.show_message( "Exporting History '%(n)s'. Use this link to download \
the archive or import it to another Galaxy server: \
<a href='%(u)s'>%(u)s</a>" % ( { 'n' : history.name, 'u' : url } ) )
#TODO: used in this file and index.mako
@web.expose
@web.json
@web.require_login( "get history name and link" )
def get_name_and_link_async( self, trans, id=None ):
""" Returns history's name and link. """
history = self.get_history( trans, id, False )
if self.create_item_slug( trans.sa_session, history ):
trans.sa_session.flush()
return_dict = {
"name" : history.name,
"link" : url_for(controller='history', action="display_by_username_and_slug",
username=history.user.username, slug=history.slug ) }
return return_dict
#TODO: used in page/editor.mako
@web.expose
@web.require_login( "set history's accessible flag" )
def set_accessible_async( self, trans, id=None, accessible=False ):
""" Set history's importable attribute and slug. """
history = self.get_history( trans, id, True )
# Only set if importable value would change; this prevents a change in the update_time unless attribute really changed.
importable = accessible in ['True', 'true', 't', 'T'];
if history and history.importable != importable:
if importable:
self._make_item_accessible( trans.sa_session, history )
else:
history.importable = importable
trans.sa_session.flush()
return
#TODO: used in page/editor.mako
@web.expose
def get_item_content_async( self, trans, id ):
""" Returns item content in HTML format. """
history = self.get_history( trans, id, False, True )
if history is None:
raise web.httpexceptions.HTTPNotFound()
# Get datasets.
datasets = self.get_history_datasets( trans, history )
# Get annotations.
history.annotation = self.get_item_annotation_str( trans.sa_session, history.user, history )
for dataset in datasets:
dataset.annotation = self.get_item_annotation_str( trans.sa_session, history.user, dataset )
return trans.stream_template_mako( "/history/item_content.mako", item = history, item_data = datasets )
#TODO: used in embed_base.mako
@web.expose
def name_autocomplete_data( self, trans, q=None, limit=None, timestamp=None ):
"""Return autocomplete data for history names"""
user = trans.get_user()
if not user:
return
ac_data = ""
for history in ( trans.sa_session.query( model.History )
.filter_by( user=user )
.filter( func.lower( model.History.name ).like(q.lower() + "%") ) ):
ac_data = ac_data + history.name + "\n"
return ac_data
#TODO: used in grid_base.mako
@web.expose
def imp( self, trans, id=None, confirm=False, **kwd ):
"""Import another user's history via a shared URL"""
msg = ""
user = trans.get_user()
user_history = trans.get_history()
# Set referer message
if 'referer' in kwd:
referer = kwd['referer']
else:
referer = trans.request.referer
if referer is not "":
referer_message = "<a href='%s'>return to the previous page</a>" % referer
else:
referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
# include all datasets when copying?
all_datasets = util.string_as_bool( kwd.get( 'all_datasets', False ) )
# Do import.
if not id:
return trans.show_error_message( "You must specify a history you want to import.<br>You can %s." % referer_message, use_panels=True )
import_history = self.get_history( trans, id, check_ownership=False, check_accessible=False )
if not import_history:
return trans.show_error_message( "The specified history does not exist.<br>You can %s." % referer_message, use_panels=True )
# History is importable if user is admin or it's accessible. TODO: probably want to have app setting to enable admin access to histories.
if not trans.user_is_admin() and not self.security_check( trans, import_history, check_ownership=False, check_accessible=True ):
return trans.show_error_message( "You cannot access this history.<br>You can %s." % referer_message, use_panels=True )
if user:
#dan: I can import my own history.
#if import_history.user_id == user.id:
# return trans.show_error_message( "You cannot import your own history.<br>You can %s." % referer_message, use_panels=True )
new_history = import_history.copy( target_user=user, all_datasets=all_datasets )
new_history.name = "imported: " + new_history.name
new_history.user_id = user.id
galaxy_session = trans.get_galaxy_session()
try:
association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \
.filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \
.first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
trans.sa_session.add( new_history )
trans.sa_session.flush()
# Set imported history to be user's current history.
trans.set_history( new_history )
return trans.show_ok_message(
message="""History "%s" has been imported. <br>You can <a href="%s" onclick="parent.window.location='%s';">start using this history</a> or %s."""
% ( new_history.name, web.url_for( '/' ), web.url_for( '/' ), referer_message ), use_panels=True )
elif not user_history or not user_history.datasets or confirm:
#TODO:?? should anon-users be allowed to include deleted datasets when importing?
#new_history = import_history.copy( activatable=include_deleted )
new_history = import_history.copy()
new_history.name = "imported: " + new_history.name
new_history.user_id = None
galaxy_session = trans.get_galaxy_session()
try:
association = trans.sa_session.query( trans.app.model.GalaxySessionToHistoryAssociation ) \
.filter_by( session_id=galaxy_session.id, history_id=new_history.id ) \
.first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
trans.sa_session.add( new_history )
trans.sa_session.flush()
trans.set_history( new_history )
return trans.show_ok_message(
message="""History "%s" has been imported. <br>You can <a href="%s">start using this history</a> or %s."""
% ( new_history.name, web.url_for( '/' ), referer_message ), use_panels=True )
return trans.show_warn_message( """
Warning! If you import this history, you will lose your current
history. <br>You can <a href="%s">continue and import this history</a> or %s.
""" % ( web.url_for(controller='history', action='imp', id=id, confirm=True, referer=trans.request.referer ), referer_message ), use_panels=True )
#TODO: used in history/view, display, embed
@web.expose
@web.require_login( "rename histories" )
def rename( self, trans, id=None, name=None, **kwd ):
@@ -1361,7 +1354,8 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
name += " (active items only)"
new_history = history.copy( name=name, target_user=user )
if len( histories ) == 1:
msg = 'New history "<a href="%s" target="_top">%s</a>" has been created.' % ( url_for( controller="history", action="switch_to_history", hist_id=trans.security.encode_id( new_history.id ) ) , new_history.name )
switch_url = url_for( controller="history", action="switch_to_history", hist_id=trans.security.encode_id( new_history.id ) )
msg = 'New history "<a href="%s" target="_top">%s</a>" has been created.' % ( switch_url, new_history.name )
else:
msg = 'Copied and created %d new histories.' % len( histories )
return trans.show_ok_message( msg )
+16 -43
View File
@@ -7,20 +7,28 @@ import urllib
from paste.httpexceptions import HTTPNotFound, HTTPBadGateway
from galaxy.web.base.controller import BaseUIController, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin
from galaxy import managers
from galaxy import web
from galaxy.web import url_for
from galaxy.model.item_attrs import UsesAnnotations
from galaxy import util
from galaxy.util import listify, Params, string_as_bool, string_as_bool_or_none
from galaxy.web.base.controller import BaseUIController, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin
from galaxy.util.json import to_json_string
from galaxy.util.debugging import SimpleProfiler
import logging
log = logging.getLogger( __name__ )
class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAssociationMixin, UsesAnnotations ):
"""Controller class that maps to the url root of Galaxy (i.e. '/')."""
"""
Controller class that maps to the url root of Galaxy (i.e. '/').
"""
def __init__( self, app ):
super( RootController, self ).__init__( app )
self.mgrs = util.bunch.Bunch(
histories=managers.histories.HistoryManager()
)
@web.expose
def default(self, trans, target1=None, target2=None, **kwd):
@@ -100,42 +108,6 @@ class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAsso
show_deleted=string_as_bool( show_deleted ),
show_hidden=string_as_bool( show_hidden ) )
def _get_current_history_data( self, trans ):
history_dictionary = {}
hda_dictionaries = []
try:
history = trans.get_history( create=True )
hdas = self.get_history_datasets( trans, history,
show_deleted=True, show_hidden=True, show_purged=True )
for hda in hdas:
hda_dict = {}
try:
hda_dict = self.get_hda_dict( trans, hda )
except Exception, exc:
# don't fail entire list if hda err's, record and move on
log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
hda_dict = self.get_hda_dict_with_error( trans, hda, str( exc ) )
hda_dictionaries.append( hda_dict )
# re-use the hdas above to get the history data...
history_dictionary = self.get_history_dict( trans, history, hda_dictionaries=hda_dictionaries )
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
log.exception( 'Error bootstrapping history for user %s: %s', user_id, str( exc ) )
message = ( 'An error occurred getting the history data from the server. '
+ 'Please contact a Galaxy administrator if the problem persists.' )
history_dictionary[ 'error' ] = message
return {
'history' : history_dictionary,
'hdas' : hda_dictionaries
}
@web.expose
def history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, **kwd ):
"""
@@ -154,11 +126,11 @@ class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAsso
show_hidden = string_as_bool_or_none( show_hidden )
history_dictionary = {}
hda_dictionaries = []
hda_dictionaries = []
try:
history_data = self._get_current_history_data( trans )
history_data = self.mgrs.histories._get_history_data( trans, trans.get_history( create=True ) )
history_dictionary = history_data[ 'history' ]
hda_dictionaries = history_data[ 'hdas' ]
hda_dictionaries = history_data[ 'contents' ]
except Exception, exc:
user_id = str( trans.user.id ) if trans.user else '(anonymous)'
@@ -170,6 +142,7 @@ class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAsso
history = history_dictionary, hdas = hda_dictionaries,
show_deleted=show_deleted, show_hidden=show_hidden )
## ---- Dataset display / editing ----------------------------------------
@web.expose
def display( self, trans, id=None, hid=None, tofile=None, toext=".txt", encoded_id=None, **kwd ):