diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 70a28e80766..e18f3fcdd87 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -632,7 +632,8 @@ class HistoryDatasetAssociation( DatasetInstance ): visible=self.visible, deleted=self.deleted, parent_id=parent_id, - copied_from_history_dataset_association=self ) + copied_from_history_dataset_association=self, + user=self.history.user ) ldda.flush() # Must set metadata after flushed, as MetadataFiles require dataset.id ldda.metadata = self.metadata @@ -737,11 +738,17 @@ class LibraryDataset( object ): return template_list class LibraryDatasetDatasetAssociation( DatasetInstance ): - def __init__( self, copied_from_history_dataset_association=None, copied_from_library_dataset_dataset_association=None, library_dataset=None, **kwd ): + def __init__( self, + copied_from_history_dataset_association=None, + copied_from_library_dataset_dataset_association=None, + library_dataset=None, + user=None, + **kwd ): DatasetInstance.__init__( self, **kwd ) self.copied_from_history_dataset_association = copied_from_history_dataset_association self.copied_from_library_dataset_dataset_association = copied_from_library_dataset_dataset_association self.library_dataset = library_dataset + self.user = user def to_history_dataset_association( self, target_history, parent_id=None ): hid = target_history._next_hid() hda = HistoryDatasetAssociation( name=self.name, @@ -829,38 +836,44 @@ class LibraryItemInfoTemplateElement( object ): pass class LibraryInfoAssociation( object ): - def set_library_item( self, library_item, user ): + def __init__( self, user=None ): + self.user = user + def set_library_item( self, library_item ): if isinstance( library_item, Library ): self.library = library_item - self.user = user else: raise "Invalid Library specified: %s" % library_item.__class__.__name__ class LibraryFolderInfoAssociation( object ): - def set_library_item( self, library_item, user ): + def __init__( self, user=None ): + self.user = user + def set_library_item( self, library_item ): if isinstance( library_item, LibraryFolder ): self.folder = library_item - self.user = user else: raise "Invalid Library specified: %s" % library_item.__class__.__name__ class LibraryDatasetInfoAssociation( object ): - def set_library_item( self, library_item, user ): + def __init__( self, user=None ): + self.user = user + def set_library_item( self, library_item ): if isinstance( library_item, LibraryDataset ): self.library_dataset = library_item - self.user = user else: raise "Invalid Library specified: %s" % library_item.__class__.__name__ class LibraryDatasetDatasetInfoAssociation( object ): - def set_library_item( self, library_item, user ): + def __init__( self, user=None ): + self.user = user + def set_library_item( self, library_item ): if isinstance( library_item, LibraryDatasetDatasetAssociation ): self.library_dataset_dataset_association = library_item - self.user = user else: raise "Invalid Library specified: %s" % library_item.__class__.__name__ class LibraryItemInfo( object ): + def __init__( self, user=None ): + self.user = user def get_element_by_template_element( self, template_element ): for element in self.elements: if element.library_item_info_template_element == template_element: diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py index d416e00acd4..1171de4bcd8 100644 --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -240,7 +240,9 @@ LibraryDatasetDatasetAssociation.table = Table( "library_dataset_dataset_associa Column( "parent_id", Integer, ForeignKey( "library_dataset_dataset_association.id" ), nullable=True ), Column( "designation", TrimmedString( 255 ) ), Column( "deleted", Boolean, index=True, default=False ), - Column( "visible", Boolean ) ) + Column( "visible", Boolean ), + Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), + Column( "message", TrimmedString( 255 ) ) ) Library.table = Table( "library", metadata, Column( "id", Integer, primary_key=True ), @@ -711,6 +713,7 @@ assign_mapper( context, LibraryDatasetDatasetAssociation, LibraryDatasetDatasetA dataset=relation( Dataset ), library_dataset = relation( LibraryDataset, primaryjoin=( LibraryDatasetDatasetAssociation.table.c.library_dataset_id == LibraryDataset.table.c.id ) ), + user=relation( User.mapper ), copied_to_library_dataset_dataset_associations=relation( LibraryDatasetDatasetAssociation, primaryjoin=( LibraryDatasetDatasetAssociation.table.c.copied_from_library_dataset_dataset_association_id == LibraryDatasetDatasetAssociation.table.c.id ), @@ -761,26 +764,31 @@ assign_mapper( context, LibraryItemInfoElement, LibraryItemInfoElement.table, assign_mapper( context, LibraryItemInfo, LibraryItemInfo.table, properties=dict( library_item_info_template=relation( LibraryItemInfoTemplate, backref="library_item_infos" ), + user=relation( User.mapper ) ) ) assign_mapper( context, LibraryInfoAssociation, LibraryInfoAssociation.table, properties=dict( library=relation( Library, backref="library_info_associations" ), library_item_info = relation( LibraryItemInfo, backref="library_info_associations" ), + user=relation( User.mapper ) ) ) assign_mapper( context, LibraryFolderInfoAssociation, LibraryFolderInfoAssociation.table, properties=dict( folder=relation( LibraryFolder, backref="library_folder_info_associations" ), library_item_info = relation( LibraryItemInfo, backref="library_folder_info_associations" ), + user=relation( User.mapper ) ) ) assign_mapper( context, LibraryDatasetInfoAssociation, LibraryDatasetInfoAssociation.table, properties=dict( library_dataset=relation( LibraryDataset, backref="library_dataset_info_associations" ), library_item_info = relation( LibraryItemInfo, backref="library_dataset_info_associations" ), + user=relation( User.mapper ) ) ) assign_mapper( context, LibraryDatasetDatasetInfoAssociation, LibraryDatasetDatasetInfoAssociation.table, properties=dict( library_dataset_dataset_association = relation( LibraryDatasetDatasetAssociation, backref="library_dataset_dataset_info_associations" ), library_item_info = relation( LibraryItemInfo, backref="library_dataset_dataset_info_associations" ), + user=relation( User.mapper ) ) ) assign_mapper( context, JobToInputDatasetAssociation, JobToInputDatasetAssociation.table, diff --git a/lib/galaxy/web/controllers/admin.py b/lib/galaxy/web/controllers/admin.py index a27a81c5bef..e7e69034a8b 100644 --- a/lib/galaxy/web/controllers/admin.py +++ b/lib/galaxy/web/controllers/admin.py @@ -927,6 +927,8 @@ class Admin( BaseController ): permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles trans.app.security_agent.set_all_library_permissions( library, permissions ) library.refresh() + # Copy the permissions to the root folder + trans.app.security_agent.copy_library_permissions( library, library.root_folder, user=trans.get_user() ) msg = "Permissions updated for library '%s'" % library.name return trans.response.send_redirect( web.url_for( controller='admin', action='library', @@ -1349,12 +1351,14 @@ class Admin( BaseController ): old_name = ldda.name new_name = util.restore_text( params.get( 'name', '' ) ) new_info = util.restore_text( params.get( 'info', '' ) ) + new_message = util.restore_text( params.get( 'message', '' ) ) if not new_name: msg = 'Enter a valid name' messagetype = 'error' else: ldda.name = new_name ldda.info = new_info + ldda.message = new_message # The following for loop will save all metadata_spec items for name, spec in ldda.datatype.metadata_spec.items(): if spec.get("readonly"): @@ -1808,12 +1812,7 @@ class Admin( BaseController ): library_item = trans.app.model.LibraryDatasetDatasetAssociation.get( library_item_id ) # This response_action method requires a folder_id folder_id = library_item.library_dataset.folder.id - elif library_item_type == 'library_item_info_elememt': - library_item = trans.app.model.LibraryItemInfoElement.get( int( id ) ) else: - library_item_type == None - library_item = None - if not library_item: msg = "Invalid library item type ( %s ) specified, id ( %s )" % ( str( library_item_type ), str( library_item_id ) ) return trans.response.send_redirect( web.url_for( controller='admin', action='browse_library', @@ -1843,9 +1842,8 @@ class Admin( BaseController ): msg=util.sanitize_text( msg ), messagetype='error' ) ) user = trans.get_user() - library_item_info = trans.app.model.LibraryItemInfo() + library_item_info = trans.app.model.LibraryItemInfo( user=user ) library_item_info.library_item_info_template = library_item_info_template - library_item_info.user = user library_item_info.flush() trans.app.security_agent.copy_library_permissions( library_item_info_template, library_item_info ) for template_element in library_item_info_template.elements: @@ -1860,10 +1858,9 @@ class Admin( BaseController ): if isinstance( library_item, item_class ): break if info_association_class: - library_item_info_association = info_association_class() - library_item_info_association.set_library_item( library_item, trans.user ) + library_item_info_association = info_association_class( user=user ) + library_item_info_association.set_library_item( library_item ) library_item_info_association.library_item_info = library_item_info - library_item_info_association.user = user library_item_info_association.flush() else: raise 'Invalid class (%s) specified for library_item (%s)' % ( library_item.__class__, library_item.__class__.__name__ ) @@ -1884,9 +1881,12 @@ class Admin( BaseController ): messagetype=messagetype ) elif params.get( 'edit_info', False ): if params.get( 'edit_info_button', False ): - new_contents = util.restore_text( params.get( ( 'info_element_%s' % id ), '' ) ) - library_item.contents = new_contents - library_item.flush() + ids = util.listify( id ) + for id in ids: + library_item_info_element = trans.app.model.LibraryItemInfoElement.get( int( id ) ) + new_contents = util.restore_text( params.get( ( 'info_element_%s' % id ), '' ) ) + library_item_info_element.contents = new_contents + library_item_info_element.flush() msg = 'The information has been updated.' return trans.response.send_redirect( web.url_for( controller='admin', action=library_item_type, diff --git a/lib/galaxy/web/controllers/library.py b/lib/galaxy/web/controllers/library.py index ba62b8dfd57..5916ed01b6f 100644 --- a/lib/galaxy/web/controllers/library.py +++ b/lib/galaxy/web/controllers/library.py @@ -132,6 +132,8 @@ class Library( BaseController ): permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles trans.app.security_agent.set_all_library_permissions( library, permissions ) library.refresh() + # Copy the permissions to the root folder + trans.app.security_agent.copy_library_permissions( library, library.root_folder, user=trans.get_user() ) msg = "Permissions updated for library '%s'" % library.name return trans.response.send_redirect( web.url_for( controller='library', action='library', @@ -523,12 +525,14 @@ class Library( BaseController ): old_name = ldda.name new_name = util.restore_text( params.get( 'name', '' ) ) new_info = util.restore_text( params.get( 'info', '' ) ) + new_message = util.restore_text( params.get( 'message', '' ) ) if not new_name: msg = 'Enter a valid name' messagetype = 'error' else: ldda.name = new_name ldda.info = new_info + ldda.message = new_message # The following for loop will save all metadata_spec items for name, spec in ldda.datatype.metadata_spec.items(): if spec.get("readonly"): @@ -1239,12 +1243,7 @@ class Library( BaseController ): library_item = trans.app.model.LibraryDatasetDatasetAssociation.get( library_item_id ) # This response_action method requires a folder_id folder_id = library_item.library_dataset.folder.id - elif library_item_type == 'library_item_info_elememt': - library_item = trans.app.model.LibraryItemInfoElement.get( int( id ) ) else: - library_item_type == None - library_item = None - if not library_item: msg = "Invalid library item type ( %s ) specified, id ( %s )" % ( str( library_item_type ), str( library_item_id ) ) return trans.response.send_redirect( web.url_for( controller='library', action='browse_library', @@ -1274,9 +1273,8 @@ class Library( BaseController ): msg=util.sanitize_text( msg ), messagetype='error' ) ) user = trans.get_user() - library_item_info = trans.app.model.LibraryItemInfo() + library_item_info = trans.app.model.LibraryItemInfo( user=user ) library_item_info.library_item_info_template = library_item_info_template - library_item_info.user = user library_item_info.flush() trans.app.security_agent.copy_library_permissions( library_item_info_template, library_item_info ) for template_element in library_item_info_template.elements: @@ -1291,10 +1289,9 @@ class Library( BaseController ): if isinstance( library_item, item_class ): break if info_association_class: - library_item_info_association = info_association_class() - library_item_info_association.set_library_item( library_item, trans.user ) + library_item_info_association = info_association_class( user=user ) + library_item_info_association.set_library_item( library_item ) library_item_info_association.library_item_info = library_item_info - library_item_info_association.user = user library_item_info_association.flush() else: raise 'Invalid class (%s) specified for library_item (%s)' % ( library_item.__class__, library_item.__class__.__name__ ) @@ -1315,9 +1312,12 @@ class Library( BaseController ): messagetype=messagetype ) elif params.get( 'edit_info', False ): if params.get( 'edit_info_button', False ): - new_contents = util.restore_text( params.get( ( 'info_element_%s' % id ), '' ) ) - library_item.contents = new_contents - library_item.flush() + ids = util.listify( id ) + for id in ids: + library_item_info_element = trans.app.model.LibraryItemInfoElement.get( int( id ) ) + new_contents = util.restore_text( params.get( ( 'info_element_%s' % id ), '' ) ) + library_item_info_element.contents = new_contents + library_item_info_element.flush() msg = 'The information has been updated.' return trans.response.send_redirect( web.url_for( controller='library', action=library_item_type, diff --git a/lib/galaxy/web/controllers/library_dataset.py b/lib/galaxy/web/controllers/library_dataset.py index e72824420f6..abf2b1afaa4 100644 --- a/lib/galaxy/web/controllers/library_dataset.py +++ b/lib/galaxy/web/controllers/library_dataset.py @@ -12,7 +12,8 @@ class UploadLibraryDataset( BaseController ): os.unlink( filename ) except: log.exception( 'failure removing temporary file: %s' % filename ) - def add_file( self, trans, folder_id, file_obj, name, file_format, dbkey, roles, info='no info', space_to_tab=False, replace_dataset=None ): + def add_file( self, trans, folder_id, file_obj, name, file_format, dbkey, roles, info='no info', space_to_tab=False, + replace_dataset=None, library_item_info_template=None, template_elements={}, message=None ): folder = trans.app.model.LibraryFolder.get( folder_id ) data_type = None line_count = 0 @@ -111,7 +112,9 @@ class UploadLibraryDataset( BaseController ): extension=data_type, dbkey=dbkey, library_dataset=library_dataset, + user=trans.get_user(), create_dataset=True ) + ldda.message = message ldda.flush() # Permissions must be the same on the LibraryDatasetDatasetAssociation and the associated LibraryDataset trans.app.security_agent.copy_library_permissions( library_dataset, ldda ) @@ -124,6 +127,24 @@ class UploadLibraryDataset( BaseController ): folder.add_library_dataset( library_dataset, genome_build=dbkey ) library_dataset.library_dataset_dataset_association_id = ldda.id library_dataset.flush() + # Handle any templates included in the upload form + if library_item_info_template: + user = trans.get_user() + library_item_info = trans.app.model.LibraryItemInfo( user=user ) + library_item_info.library_item_info_template = library_item_info_template + library_item_info.flush() + trans.app.security_agent.copy_library_permissions( library_item_info_template, library_item_info ) + for template_element in library_item_info_template.elements: + info_element_value = template_elements.get( "info_element_%s_%s" % ( library_item_info_template.id, template_element.id ), None ) + info_element = trans.app.model.LibraryItemInfoElement() + info_element.contents = info_element_value + info_element.library_item_info_template_element = template_element + info_element.library_item_info = library_item_info + info_element.flush() + library_item_info_association = trans.app.model.LibraryDatasetDatasetInfoAssociation( user=user ) + library_item_info_association.set_library_item( ldda ) + library_item_info_association.library_item_info = library_item_info + library_item_info_association.flush() # If roles were selected upon upload, restrict access to the Dataset to those roles if roles: for role in roles: @@ -160,6 +181,22 @@ class UploadLibraryDataset( BaseController ): replace_id = replace_dataset.id else: replace_id = None + message = params.get( 'message', '' ) + # Handle any templates included in the upload form by building a dictionary of info elements to send to add_file + template_elements = {} + library_item_info_template = None + library_item_info_template_id = params.get( 'library_item_info_template_id', None ) + if library_item_info_template_id: + library_item_info_template = trans.app.model.LibraryItemInfoTemplate.get( int( library_item_info_template_id ) ) + for template_element in library_item_info_template.elements: + # Make sure at least 1 template field is filled in + # TODO: Eventually we'll enhance templates to allow for required and optional fields. + if params.get( "info_element_%s_%s" % ( library_item_info_template.id, template_element.id ), None ): + for template_element in library_item_info_template.elements: + key = "info_element_%s_%s" % ( library_item_info_template.id, template_element.id ) + value = params.get( key, None ) + if value: + template_elements[ key ] = value if data_file == '' and url_paste == '' and server_dir in [ 'None', '' ]: if trans.app.config.library_import_dir is not None: msg = 'Select a file, enter a URL or Text, or select a server directory.' @@ -194,7 +231,10 @@ class UploadLibraryDataset( BaseController ): roles, info="uploaded file", space_to_tab=space_to_tab, - replace_dataset=replace_dataset ) + replace_dataset=replace_dataset, + library_item_info_template=library_item_info_template, + template_elements=template_elements, + message=message ) created_ldda_ids = str( created_ldda.id ) except Exception, e: log.exception( 'exception in upload_dataset using file_name %s: %s' % ( str( file_name ), str( e ) ) ) @@ -202,9 +242,13 @@ class UploadLibraryDataset( BaseController ): elif url_paste not in [ None, "" ]: if url_paste.lower().find( 'http://' ) >= 0 or url_paste.lower().find( 'ftp://' ) >= 0: url_paste = url_paste.replace( '\r', '' ).split( '\n' ) + # If we are setting the name from the line, it needs to be the line that creates that dataset + name_set_from_line = False for line in url_paste: line = line.rstrip( '\r\n' ) if line: + if not line or name_set_from_line: + name_set_from_line = True try: created_ldda = self.add_file( trans, folder_id, @@ -215,7 +259,10 @@ class UploadLibraryDataset( BaseController ): roles, info="uploaded url", space_to_tab=space_to_tab, - replace_dataset=replace_dataset ) + replace_dataset=replace_dataset, + library_item_info_template=library_item_info_template, + template_elements=template_elements, + message=message ) created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( created_ldda.id ) ) except Exception, e: log.exception( 'exception in upload_dataset using url_paste %s' % str( e ) ) @@ -238,7 +285,10 @@ class UploadLibraryDataset( BaseController ): roles, info="pasted entry", space_to_tab=space_to_tab, - replace_dataset=replace_dataset ) + replace_dataset=replace_dataset, + library_item_info_template=library_item_info_template, + template_elements=template_elements, + message=message ) created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( created_ldda.id ) ) except Exception, e: log.exception( 'exception in add_file using StringIO.StringIO( url_paste ) %s' % str( e ) ) @@ -263,7 +313,10 @@ class UploadLibraryDataset( BaseController ): roles, info="imported file", space_to_tab=space_to_tab, - replace_dataset=replace_dataset ) + replace_dataset=replace_dataset, + library_item_info_template=library_item_info_template, + template_elements=template_elements, + message=message ) created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( created_ldda.id ) ) except Exception, e: log.exception( 'exception in add_file using server_dir %s' % str( e ) ) diff --git a/templates/admin/library/common.mako b/templates/admin/library/common.mako index 20413279dee..2b4a817f215 100644 --- a/templates/admin/library/common.mako +++ b/templates/admin/library/common.mako @@ -138,7 +138,7 @@ %endif %def> -<%def name="render_available_templates( library_item, library_id, restrict=False )"> +<%def name="render_available_templates( library_item, library_id, restrict=False, upload=False )"> <% available_templates = library_item.get_library_item_info_templates( template_list=[], restrict=restrict ) if available_templates: @@ -166,26 +166,31 @@