From a8cd7a9118ca1396246c634ba8b24c3a1fd36da7 Mon Sep 17 00:00:00 2001 From: Greg Von Kuster Date: Tue, 18 Nov 2008 17:10:16 -0500 Subject: [PATCH 1/3] Streamline the process of adding datasets to a library and then updating roles and permissions on them, improve admin GUI flow, more functional tests. --- lib/galaxy/web/controllers/admin.py | 172 ++++----- .../admin/dataset_security/group_create.mako | 2 +- .../group_dataset_permitted_actions_edit.mako | 73 ---- .../admin/dataset_security/role_create.mako | 4 +- templates/admin/dataset_security/roles.mako | 2 - .../library/add_dataset_from_history.mako | 40 +- templates/admin/library/browser.mako | 21 +- templates/admin/library/common.mako | 150 ++++---- templates/admin/library/dataset.mako | 28 +- templates/admin/library/new_dataset.mako | 8 +- templates/admin/library/new_folder.mako | 10 +- templates/admin/library/new_library.mako | 8 +- templates/admin/library/rename_folder.mako | 10 +- templates/admin/library/rename_library.mako | 12 +- templates/dataset/copy_view.mako | 8 +- templates/dataset/edit_attributes.mako | 349 +++++++++--------- templates/dataset/security_common.mako | 100 ++--- templates/history/permissions.mako | 2 +- templates/user/permissions.mako | 2 +- test-data/library/3.bed | 25 ++ test-data/library/4.bed | 1 + test-data/library/5.bed | 134 +++++++ test/base/twilltestcase.py | 48 +++ test/functional/__init__.py | 1 + .../functional/test_security_and_libraries.py | 54 +-- 25 files changed, 712 insertions(+), 552 deletions(-) delete mode 100644 templates/admin/dataset_security/group_dataset_permitted_actions_edit.mako create mode 100644 test-data/library/3.bed create mode 100644 test-data/library/4.bed create mode 100644 test-data/library/5.bed diff --git a/lib/galaxy/web/controllers/admin.py b/lib/galaxy/web/controllers/admin.py index d96588f41f1..5394848f080 100644 --- a/lib/galaxy/web/controllers/admin.py +++ b/lib/galaxy/web/controllers/admin.py @@ -13,8 +13,6 @@ import sqlalchemy as sa import logging log = logging.getLogger( __name__ ) -entities = { '@': 'FuNkYaT' } -unentities = { 'FuNkYaT' : '@' } no_privilege_msg = "You must have Galaxy administrator privileges to use this feature." class Admin( BaseController ): @@ -603,9 +601,11 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + created_lfda_ids = params.get( 'created_lfda_ids', '' ) return trans.fill_template( '/admin/library/browser.mako', libraries=trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \ .order_by( trans.app.model.Library.name ).all(), + created_lfda_ids=created_lfda_ids, deleted=False, msg=msg ) libraries = library_browser @@ -622,9 +622,11 @@ class Admin( BaseController ): elif params.get( 'delete', False ): action = 'delete' else: - return trans.show_error_message( "You must specify a valid action ( new, rename, delete ) to perform on a library." ) + msg = "You must specify a valid action ( new, rename, delete ) to perform on a library." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) if not id and not action == 'new': - return trans.show_error_message( "You must specify a library to %s." % action ) + msg = "You must specify a library to %s." % action + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) if not action == 'new': library = trans.app.model.Library.get( int( id ) ) if action == 'new': @@ -741,10 +743,12 @@ class Admin( BaseController ): elif params.get( 'delete', False ): action = 'delete' else: - return trans.show_error_message( "You must specify a valid action ( new, rename, delete ) to perform on a folder." ) + msg = "You must specify a valid action ( new, rename, delete ) to perform on a folder." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) folder = trans.app.model.LibraryFolder.get( id ) if not folder: - return trans.show_error_message( "Invalid folder specified, id: %s" % str( id ) ) + msg = "Invalid folder specified, id: %s" % str( id ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) if action == 'new': if params.new == 'submitted': new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ), @@ -862,7 +866,6 @@ class Admin( BaseController ): # Dataset upload if params.get( 'new_dataset_button', False ): # Copied from upload tool action - last_dataset_created = None data_file = params.get( 'file_data', '' ) url_paste = params.get( 'url_paste', '' ) server_dir = params.get( 'server_dir', 'None' ) @@ -881,34 +884,35 @@ class Admin( BaseController ): roles.append( galaxy.model.Role.get( role_id ) ) temp_name = "" data_list = [] - created_datasets = [] + created_lfda_ids = '' if 'filename' in dir( data_file ): file_name = data_file.filename file_name = file_name.split( '\\' )[-1] file_name = file_name.split( '/' )[-1] - last_dataset_created = add_file( data_file.file, - file_name, - extension, - dbkey, - last_used_build, - roles, - info="uploaded file", - space_to_tab=space_to_tab ) + created_lfda = add_file( data_file.file, + file_name, + extension, + dbkey, + last_used_build, + roles, + info="uploaded file", + space_to_tab=space_to_tab ) + created_lfda_ids = str( created_lfda.id ) 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' ) for line in url_paste: line = line.rstrip( '\r\n' ) if line: - last_dataset_created = add_file( urllib.urlopen( line ), - line, - extension, - dbkey, - last_used_build, - roles, - info="uploaded url", - space_to_tab=space_to_tab ) - created_datasets.append( last_dataset_created ) + created_lfda = add_file( urllib.urlopen( line ), + line, + extension, + dbkey, + last_used_build, + roles, + info="uploaded url", + space_to_tab=space_to_tab ) + created_lfda_ids = '%s,%s' % ( created_lfda_ids, str( created_lfda.id ) ) else: is_valid = False for line in url_paste: @@ -917,14 +921,15 @@ class Admin( BaseController ): is_valid = True break if is_valid: - last_dataset_created = add_file( StringIO.StringIO( url_paste ), - 'Pasted Entry', - extension, - dbkey, - last_used_build, - roles, - info="pasted entry", - space_to_tab=space_to_tab ) + created_lfda = add_file( StringIO.StringIO( url_paste ), + 'Pasted Entry', + extension, + dbkey, + last_used_build, + roles, + info="pasted entry", + space_to_tab=space_to_tab ) + created_lfda_ids = '%s,%s' % ( created_lfda_ids, str( created_lfda.id ) ) elif server_dir not in [ None, "", "None" ]: full_dir = os.path.join( trans.app.config.library_import_dir, server_dir ) try: @@ -935,31 +940,23 @@ class Admin( BaseController ): full_file = os.path.join( full_dir, file ) if not os.path.isfile( full_file ): continue - last_dataset_created = add_file( open( full_file, 'rb' ), - file, - extension, - dbkey, - last_used_build, - roles, - info="imported file", - space_to_tab=space_to_tab ) - created_datasets.append( last_dataset_created ) - if len( created_datasets ) > 1: - trans.response.send_redirect( web.url_for( - action = 'library_browser', - msg = "%i new datasets added to the library. Click here if you'd like to edit the permissions on these datasets." % ( - len( created_datasets ), - web.url_for( action='dataset', id=",".join( [ str(d.id) for d in created_datasets ] ) ) - ) - ) ) - elif last_dataset_created is not None: - trans.response.send_redirect( web.url_for( - action = 'library_browser', - msg = "New dataset added to the library. Click here if you'd like to edit the permissions or attributes on this dataset." % - web.url_for( action='dataset', id=last_dataset_created.id ) - ) ) + created_lfda = add_file( open( full_file, 'rb' ), + file, + extension, + dbkey, + last_used_build, + roles, + info="imported file", + space_to_tab=space_to_tab ) + created_lfda_ids = '%s,%s' % ( created_lfda_ids, str( created_lfda.id ) ) + if created_lfda_ids: + created_lfda_ids = created_lfda_ids.lstrip( ',' ) + total_added = len( created_lfda_ids.split( ',' ) ) + msg = "%i new datasets added to the library ( each is selected below ). Click the Go button at the bottom of this page to edit the permissions on these datasets." % total_added + trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg ) ) else: - return trans.show_error_message( 'Upload failed' ) + msg = "Upload failed" + trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg ) ) # No dataset(s) specified, display upload form elif not id: @@ -971,7 +968,7 @@ class Admin( BaseController ): yield build_name, dbkey, ( dbkey==last_used_build ) dbkeys = get_dbkey_options( last_used_build ) # Send list of roles to the form so the dataset can be associated with 1 or more of them. - roles = trans.app.model.Role.query().order_by( trans.app.model.Role.c.name ).all() + roles = trans.app.model.Role.filter( trans.app.model.Role.c.type != trans.app.model.Role.types.PRIVATE ).order_by( trans.app.model.Role.c.name ).all() return trans.fill_template( '/admin/library/new_dataset.mako', folder_id=folder_id, file_formats=file_formats, @@ -981,7 +978,7 @@ class Admin( BaseController ): msg=msg ) else: if id.count( ',' ): - ids = id.split(',') + ids = id.split( ',' ) id = None else: ids = None @@ -989,7 +986,8 @@ class Admin( BaseController ): if id: lda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) if not lda: - return trans.show_error_message( "Invalid dataset specified, id: %s" %str( id ) ) + msg = "Invalid dataset specified, id: %s" %str( id ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) # Copied from edit attributes for 'regular' datasets with some additions p = util.Params(kwd, safe=False) @@ -1056,36 +1054,40 @@ class Admin( BaseController ): datatypes=ldatatypes, err=None, msg=msg ) - # multiple ids specfied, display multi permission form + # multiple ids specfied, display permission form for each one... elif ids: - ldas = [] + lfdas = [] for id in [ int( id ) for id in ids ]: - lda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) - if lda is None: - return trans.show_error_message( 'You specified an invalid dataset' ) - ldas.append( lda ) - if len( ldas ) < 2: - return trans.show_error_message( 'You must specify at least two datasets to modify permissions on' ) + lfda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) + if lfda is None: + msg = 'You specified an invalid dataset id: %s' %str( id ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + lfdas.append( lfda ) + if len( lfdas ) < 2: + msg = 'You must specify at least two datasets on which to modify permissions, ids you sent: %s' % str( ids ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) if 'update_roles' in kwd: - p = util.Params( kwd ) + #p = util.Params( kwd ) permissions = {} for k, v in trans.app.model.Dataset.permitted_actions.items(): - in_roles = [ trans.app.model.Role.get( x ) for x in listify( p.get( k + '_in', [] ) ) ] + in_roles = [ trans.app.model.Role.get( x ) for x in listify( params.get( k + '_in', [] ) ) ] permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles - for lda in ldas: - trans.app.security_agent.set_dataset_permissions( lda.dataset, permissions ) - lda.dataset.refresh() - # Ensure that the permissions across all datasets are identical. Otherwise, we can't update together. + for lfda in lfdas: + trans.app.security_agent.set_dataset_permissions( lfda.dataset, permissions ) + lfda.dataset.refresh() + msg = 'Permissions and roles have been updated on %d datasets' % len( lfdas ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + # Ensure that the permissions across all datasets are identical. Otherwise, we can't update together. tmp = [] - for lda in ldas: - perms = trans.app.security_agent.get_dataset_permissions( lda.dataset ) + for lfda in lfdas: + perms = trans.app.security_agent.get_dataset_permissions( lfda.dataset ) if perms not in tmp: tmp.append( perms ) if len( tmp ) != 1: - return trans.show_error_message( "The datasets you selected do not have identical permissions, so they can not be updated together" ) + msg = 'The datasets you selected do not have identical permissions, so they can not be updated together' + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) else: - return trans.fill_template( "/admin/library/dataset.mako", - dataset=ldas ) + return trans.fill_template( "/admin/library/dataset.mako", dataset=lfdas ) @web.expose def add_dataset_to_folder_from_history( self, trans, ids="", folder_id=None, **kwd ): if not isinstance( ids, list ): @@ -1098,7 +1100,8 @@ class Admin( BaseController ): except: folder = None if folder is None: - return trans.show_error_message( "You must provide a valid target folder." ) + msg = "You must provide a valid target folder." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) error_msg = ok_msg = "" dataset_names = [] if ids: @@ -1169,7 +1172,8 @@ class Admin( BaseController ): self._delete_dataset( library_folder_dataset_assoc ) trans.log_event( "Dataset id %s deleted from library folder id %s" % ( str( id ), str( library_folder_dataset_assoc.folder.id ) ) ) trans.response.send_redirect( web.url_for( action = 'folder', id = library_folder_dataset_assoc.folder.id, msg = 'The dataset was deleted from the folder' ) ) - return trans.show_error_message( "You did not specify a dataset to delete." ) + msg = "You did not specify a dataset to delete." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) def _delete_dataset( self, library_folder_dataset_assoc ): #dataset = library_folder_dataset_assoc.dataset @@ -1204,7 +1208,8 @@ class Admin( BaseController ): if folder.library_root: trans.response.send_redirect( web.url_for( action = 'library', id = folder.library_root[0].id, msg = 'You have deleted the root folder.' ) ) trans.response.send_redirect( web.url_for( action = 'folder', id = folder.parent_id, msg = 'The folder was deleted.' ) ) - return trans.show_error_message( "You did not specify a folder to delete." ) + msg = "You did not specify a folder to delete." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) def _delete_folder( self, folder ): for lfda in folder.active_datasets: @@ -1228,7 +1233,8 @@ class Admin( BaseController ): library.flush() trans.log_event( "Library id %s deleted." % id ) trans.response.send_redirect( web.url_for( action = 'libraries', msg = 'You have deleted the library %s.' % library.id ) ) - return trans.show_error_message( "You did not specify a library to delete." ) + msg = "You did not specify a library to delete." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) @web.expose def memdump( self, trans, ids = 'None', sorts = 'None', pages = 'None', new_id = None, new_sort = None, **kwd ): diff --git a/templates/admin/dataset_security/group_create.mako b/templates/admin/dataset_security/group_create.mako index 88c61d41840..50aca838830 100644 --- a/templates/admin/dataset_security/group_create.mako +++ b/templates/admin/dataset_security/group_create.mako @@ -38,7 +38,7 @@
- + <% render_quick_find = len( users ) > 50 ctr = 0 diff --git a/templates/admin/dataset_security/group_dataset_permitted_actions_edit.mako b/templates/admin/dataset_security/group_dataset_permitted_actions_edit.mako deleted file mode 100644 index 5afe2ae809f..00000000000 --- a/templates/admin/dataset_security/group_dataset_permitted_actions_edit.mako +++ /dev/null @@ -1,73 +0,0 @@ -<%inherit file="/base.mako"/> - -<%def name="title()">Permitted Actions on Datasets -
-
- Libraries  |   - Groups  |   -
- -

Manage Permitted Actions on Datasets for Group '${group.name}'

-
Name:
Name:
Users
- %if msg: - - %endif - - %if len( group.datasets ) == 0: - - %else: - - - - - <% ctr = 0 %> - - - %for gda in gdas: - <% permissions = trans.app.security_agent.get_dataset_permissions( gda, group.id ) %> - %if ctr % 2 == 1: - - %else: - - %endif - - - - <% ctr += 1 %> - %endfor - - - %endif -

${msg}

 
The group you selected has no associated datasets.
Association Names/InfoPermitted Actions
- %if gda.dataset.library_associations: - Library name(s):
- %endif -
    - %for da in gda.dataset.library_associations: -
  • ${da.name} (${da.info})
  • - %endfor -
- %if gda.dataset.history_associations: - History name(s):
- %endif -
    - %for da in gda.dataset.history_associations: -
  • ${da.name} (${da.info})
  • - %endfor -
-
- %for pa in trans.app.model.Dataset.permitted_actions: - <% pa_val = trans.app.security_agent.permitted_actions.__dict__[pa] %> - - ${pa_val}
${trans.app.security_agent.get_permitted_action_description(pa)}
-
- %endfor -
-
- diff --git a/templates/admin/dataset_security/role_create.mako b/templates/admin/dataset_security/role_create.mako index d1e026b670e..f9954c16488 100644 --- a/templates/admin/dataset_security/role_create.mako +++ b/templates/admin/dataset_security/role_create.mako @@ -39,8 +39,8 @@
- - + + <% render_quick_find = len( users ) > 50 diff --git a/templates/admin/dataset_security/roles.mako b/templates/admin/dataset_security/roles.mako index a606c748f1a..fe0ff71d463 100644 --- a/templates/admin/dataset_security/roles.mako +++ b/templates/admin/dataset_security/roles.mako @@ -1,8 +1,6 @@ <%inherit file="/base.mako"/> <% - from galaxy.web.controllers.admin import entities, unentities - from xml.sax.saxutils import escape, unescape import galaxy.model %> diff --git a/templates/admin/library/add_dataset_from_history.mako b/templates/admin/library/add_dataset_from_history.mako index 4bb21b01200..5a3428678d8 100644 --- a/templates/admin/library/add_dataset_from_history.mako +++ b/templates/admin/library/add_dataset_from_history.mako @@ -2,29 +2,29 @@ <%def name="title()">Add Dataset to Library from History %if error_msg: -

-

${error_msg}
-
-

+

+

${error_msg}
+
+

%endif %if ok_msg: -

-

${ok_msg}
-
-

+

+

${ok_msg}
+
+

%endif

-
Active Datasets in your current history (${history.name})
-
- - - %for dataset in history.active_datasets: -
- ${dataset.hid}: ${dataset.name} -
- %endfor - - -
+
Active Datasets in your current history (${history.name})
+
+
+ + %for dataset in history.active_datasets: +
+ ${dataset.hid}: ${dataset.name} +
+ %endfor + + +
diff --git a/templates/admin/library/browser.mako b/templates/admin/library/browser.mako index 41d798b3e38..ad385e58e4d 100644 --- a/templates/admin/library/browser.mako +++ b/templates/admin/library/browser.mako @@ -67,7 +67,7 @@ } -<%def name="render_folder( parent, parent_pad, deleted )"> +<%def name="render_folder( parent, parent_pad, deleted, created_lfda_ids )"> <% ##if not trans.app.security_agent.check_folder_contents( trans.user, parent ): ## return "" @@ -80,6 +80,11 @@ expander = "/static/images/silk/resultset_next.png" folder = "/static/images/silk/folder.png" subfolder = True + + if created_lfda_ids and not isinstance ( created_lfda_ids, list ): + created_lfda_id_list = created_lfda_ids.split( ',' ) + if created_lfda_id_list: + created_lfda_ids = [ int( lfda_id ) for lfda_id in created_lfda_id_list ] %>
  • @@ -119,11 +124,17 @@ %> %endif %for folder in parent_folders: - ${render_folder( folder, pad, deleted )} + ${render_folder( folder, pad, deleted, created_lfda_ids )} %endfor %for dataset in parent_datasets: ##%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=dataset.dataset ): -
  • ${render_dataset( dataset, deleted )}
  • + <% + if created_lfda_ids and dataset.id in created_lfda_ids: + selected = True + else: + selected = False + %> +
  • ${render_dataset( dataset, selected, deleted )}
  • ##%endif %endfor @@ -199,7 +210,7 @@
      - ${render_folder( library.root_folder, 0, deleted )} + ${render_folder( library.root_folder, 0, deleted, created_lfda_ids )}

    ##%endif @@ -209,7 +220,7 @@

    Perform action on selected datasets: diff --git a/templates/admin/library/common.mako b/templates/admin/library/common.mako index a933ce70b37..8ead836c7cc 100644 --- a/templates/admin/library/common.mako +++ b/templates/admin/library/common.mako @@ -4,7 +4,7 @@ ## Render the dataset `data` -<%def name="render_dataset( data, deleted )"> +<%def name="render_dataset( data, selected, deleted )"> <% if data.state in ['no state','',None]: data_state = "queued" @@ -17,86 +17,92 @@

    ##%endif - ## Header row for history items (name, state, action buttons) + ## Header row for history items (name, state, action buttons)
    - - %if data_state == 'running': -
    - %elif data_state != 'ok': -
    - %endif + + %if data_state == 'running': +
    + %elif data_state != 'ok': +
    + %endif
    - <%doc> -
    - display data - edit attributes - delete -
    - -
    Name: Description: Name: Description:
    - - - - -
    - - ${data.display_name()} - %if not deleted: - - - %endif - ${data.ext}${data.dbkey}${data.info}
    - - - ## Body for history items, extra info and actions, data "peek" - -
    -
    - ${data.blurb} + <%doc> +
    + display data + edit attributes + delete
    -
    - %if data.has_data: - save - %for display_app in data.datatype.get_display_types(): - <% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %> - %if len( display_links ) > 0: - | ${data.datatype.get_display_label(display_app)} - %for display_name, display_link in display_links: - ${display_name} - %endfor - %endif - %endfor - %endif -
    - %if data.peek != "no peek": -
    ${data.display_peek()}
    + + + + + + + + +
    + %if selected: + + %else: + + %endif + ${data.display_name()} + %if not deleted: + + + %endif + ${data.ext}${data.dbkey}${data.info}
    +
    + + ## Body for history items, extra info and actions, data "peek" + +
    +
    + ${data.blurb} +
    +
    + %if data.has_data: + save + %for display_app in data.datatype.get_display_types(): + <% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %> + %if len( display_links ) > 0: + | ${data.datatype.get_display_label(display_app)} + %for display_name, display_link in display_links: + ${display_name} + %endfor + %endif + %endfor %endif - ## Recurse for child datasets - %if len( data.children ) > 0: - ## FIXME: This should not be in the template, there should - ## be a 'visible_children' method on dataset. - <% - children = [] +
    + %if data.peek != "no peek": +
    ${data.display_peek()}
    + %endif + ## Recurse for child datasets + %if len( data.children ) > 0: + ## FIXME: This should not be in the template, there should + ## be a 'visible_children' method on dataset. + <% + children = [] for child in data.children: if child.visible: children.append( child ) - %> - %if len( children ) > 0: -
    - There are ${len( children )} secondary datasets. - %for idx, child in enumerate(children): - ${render_dataset( child, idx + 1 )} - %endfor -
    - %endif + %> + %if len( children ) > 0: +
    + There are ${len( children )} secondary datasets. + %for idx, child in enumerate(children): + ##${render_dataset( child, idx + 1 )} + ${ render_dataset( child, selected, deleted ) } + %endfor +
    %endif -
    + %endif
    diff --git a/templates/admin/library/dataset.mako b/templates/admin/library/dataset.mako index b8ff9597b82..d910e01b362 100644 --- a/templates/admin/library/dataset.mako +++ b/templates/admin/library/dataset.mako @@ -17,10 +17,17 @@ +<% + roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.type != trans.app.model.Role.types.PRIVATE ).all() +%> + %if isinstance( dataset, list ): - ${render_permission_form( dataset[0].dataset, h.url_for( action='dataset' ), 'id', ",".join( [ str(d.id) for d in dataset ] ), trans.app.model.Role.query().all() )} + <% + name_str = ' - ( %d of them )' % len( dataset ) + %> + ${render_permission_form( dataset[0].dataset, name_str, h.url_for( action='dataset' ), 'id', ",".join( [ str(d.id) for d in dataset ] ), roles )} %else: - ${render_permission_form( dataset.dataset, h.url_for( action='dataset' ), 'id', dataset.id, trans.app.model.Role.query().all() )} + ${render_permission_form( dataset.dataset, dataset.name, h.url_for( action='dataset' ), 'id', dataset.id, roles )} %endif %if not isinstance( dataset, list ): @@ -28,18 +35,18 @@
    Edit Attributes
    - +
    - +
    - +
    @@ -55,13 +62,13 @@ %endif %endfor
    - +
    - +
    - +
    This will inspect the dataset and attempt to correct the above column values @@ -75,7 +82,7 @@
    Change data type
    - +
    @@ -89,11 +96,10 @@
    - +

    %endif -Return to the library browser diff --git a/templates/admin/library/new_dataset.mako b/templates/admin/library/new_dataset.mako index 848051e7248..de862d3f7f1 100644 --- a/templates/admin/library/new_dataset.mako +++ b/templates/admin/library/new_dataset.mako @@ -10,11 +10,11 @@

    Create a new library dataset
    - +
    - +
    Upload a single file. Use the "Server Directory" feature below to upload an entire directory of files. @@ -52,7 +52,7 @@
    - Yes + Yes
    @@ -102,7 +102,7 @@
    - +
    diff --git a/templates/admin/library/new_folder.mako b/templates/admin/library/new_folder.mako index 262bdc3bf76..47be9f9e5a2 100644 --- a/templates/admin/library/new_folder.mako +++ b/templates/admin/library/new_folder.mako @@ -11,30 +11,30 @@
    - +
    - +
    - +
    - +
    - +
    diff --git a/templates/admin/library/new_library.mako b/templates/admin/library/new_library.mako index 3615e1e2c8d..b9609c1d6d5 100644 --- a/templates/admin/library/new_library.mako +++ b/templates/admin/library/new_library.mako @@ -11,24 +11,24 @@
    - +
    - +
    - +
    - +
    diff --git a/templates/admin/library/rename_folder.mako b/templates/admin/library/rename_folder.mako index 27e0ecb45e4..8a827f0d2b4 100644 --- a/templates/admin/library/rename_folder.mako +++ b/templates/admin/library/rename_folder.mako @@ -11,30 +11,30 @@
    - +
    - +
    - +
    - +
    - + diff --git a/templates/admin/library/rename_library.mako b/templates/admin/library/rename_library.mako index 17c7e95a2a4..acbbaeb2800 100644 --- a/templates/admin/library/rename_library.mako +++ b/templates/admin/library/rename_library.mako @@ -11,37 +11,37 @@
    - +
    - +
    - +
    - +
    - +
    - + diff --git a/templates/dataset/copy_view.mako b/templates/dataset/copy_view.mako index 97c932bac32..ba4f265ce43 100644 --- a/templates/dataset/copy_view.mako +++ b/templates/dataset/copy_view.mako @@ -25,7 +25,7 @@ if data.id in source_dataset_ids: checked = " checked" %> -
    ${data.hid}: ${data.name}
    +
    ${data.hid}: ${data.name}
    %endfor @@ -41,7 +41,7 @@ if hist == trans.get_history(): cur_history_text = " (current history)" %> -
    ${i + 1}${cur_history_text}: ${hist.name}
    +
    ${i + 1}${cur_history_text}: ${hist.name}
    %endfor %if trans.get_user(): <% @@ -50,12 +50,12 @@ checked = " checked" %>
    -
    New history named:
    +
    New history named:
    %endif
    -
    +

    diff --git a/templates/dataset/edit_attributes.mako b/templates/dataset/edit_attributes.mako index 2dfb0fa22f7..fdee84f6a87 100644 --- a/templates/dataset/edit_attributes.mako +++ b/templates/dataset/edit_attributes.mako @@ -3,201 +3,186 @@ <%def name="datatype( dataset, datatypes )"> - + <% -if isinstance( data, trans.app.model.HistoryDatasetAssociation ): - id_name = 'id' -elif isinstance( data, trans.app.model.LibraryFolderDatasetAssociation ): - id_name = 'lid' + if isinstance( data, trans.app.model.HistoryDatasetAssociation ): + id_name = 'id' + elif isinstance( data, trans.app.model.LibraryFolderDatasetAssociation ): + id_name = 'lid' %> %if ( id_name == 'id' or trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_EDIT_METADATA, dataset = data ) ): -
    -
    Edit Attributes
    -
    -
    - -
    - -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - %for name, spec in data.metadata.spec.items(): - %if spec.visible: -
    - -
    - ${data.metadata.get_html_by_name( name )} -
    -
    -
    - %endif - %endfor -
    - -
    -
    -
    - -
    - -
    -
    - This will inspect the dataset and attempt to correct the above column values - if they are not accurate. -
    -
    - %if data.missing_meta(): -
    Required metadata values are missing. Some of these values may not be editable by the user. Selecting "Auto-detect" will attempt to fix these values.
    - %endif -
    -
    - -

    - - %if id_name == 'id': - <% converters = data.get_converter_types() %> - %if len( converters ) > 0: -

    -
    Convert to new format
    +
    +
    Edit Attributes
    -
    - -
    - -
    - -
    - -
    - This will create a new dataset with the contents of this - dataset converted to a new format. -
    -
    + + +
    + +
    + +
    +
    - + +
    + +
    +
    +
    + %for name, spec in data.metadata.spec.items(): + %if spec.visible: +
    + +
    + ${data.metadata.get_html_by_name( name )} +
    +
    +
    + %endif + %endfor +
    +
    -
    -
    - -

    - %endif - %endif - - -

    -
    Change data type
    -
    -
    - -
    - -
    - ${datatype( data, datatypes )} -
    - -
    - This will change the datatype of the existing dataset - but not modify its contents. Use this if Galaxy - has incorrectly guessed the type of your dataset. -
    -
    -
    -
    - -
    -
    -
    -
    - -

    -%else: -

    -
    View Attributes
    -
    -
    - Name: ${data.name} -
    - Info: ${data.info} -
    - Data Format: ${data.ext} -
    - %for element in metadata: - ${element.spec.desc}: ${element.value[0]} -
    - %endfor -
    -
    -
    - -

    -%endif - -%if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ): - -<%namespace file="/dataset/security_common.mako" import="render_permission_form" /> -${render_permission_form( data.dataset, h.url_for( action='edit' ), id_name, data.id, trans.user.all_roles() )} - -%elif trans.user: - -

    -
    View permissions
    -
    -
    - %if data.dataset.actions: -
      - %for action, roles in trans.app.security_agent.get_dataset_permissions( data.dataset ).items(): - %if roles: -
    • ${action.description}
    • -
        - %for role in roles: -
      • ${role.name}
      • - %endfor -
      - %endif - %endfor -
    - %else: -

    This dataset is accessible by everyone (it is public).

    +
    + +
    + +
    +
    + This will inspect the dataset and attempt to correct the above column values if they are not accurate. +
    +
    + %if data.missing_meta(): +
    Required metadata values are missing. Some of these values may not be editable by the user. Selecting "Auto-detect" will attempt to fix these values.
    %endif
    -
    +

    + %if id_name == 'id': + <% converters = data.get_converter_types() %> + %if len( converters ) > 0: +

    +
    Convert to new format
    +
    +
    + +
    + +
    + +
    +
    + This will create a new dataset with the contents of this dataset converted to a new format. +
    +
    +
    +
    + +
    +
    +
    +
    +

    + %endif + %endif +

    +
    Change data type
    +
    +
    + +
    + +
    + ${datatype( data, datatypes )} +
    +
    + This will change the datatype of the existing dataset + but not modify its contents. Use this if Galaxy + has incorrectly guessed the type of your dataset. +
    +
    +
    +
    + +
    +
    +
    +
    +

    +%else: +

    +
    View Attributes
    +
    +
    + Name: ${data.name} +
    + Info: ${data.info} +
    + Data Format: ${data.ext} +
    + %for element in metadata: + ${element.spec.desc}: ${element.value[0]} +
    + %endfor +
    +
    +
    +

    +%endif +%if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ): + <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> + ${render_permission_form( data.dataset, data.name, h.url_for( action='edit' ), id_name, data.id, trans.user.all_roles() )} +%elif trans.user: +

    +
    View permissions
    +
    +
    + %if data.dataset.actions: +
      + %for action, roles in trans.app.security_agent.get_dataset_permissions( data.dataset ).items(): + %if roles: +
    • ${action.description}
    • +
        + %for role in roles: +
      • ${role.name}
      • + %endfor +
      + %endif + %endfor +
    + %else: +

    This dataset is accessible by everyone (it is public).

    + %endif +
    +
    +
    %endif diff --git a/templates/dataset/security_common.mako b/templates/dataset/security_common.mako index 73e90557708..2ebe99d157e 100644 --- a/templates/dataset/security_common.mako +++ b/templates/dataset/security_common.mako @@ -27,59 +27,59 @@
    -<%def name="render_permission_form( obj, form_url, id_name, id, all_roles )"> -<% - if isinstance( obj, trans.app.model.User ): - current_actions = obj.default_permissions - elif isinstance( obj, trans.app.model.History ): - current_actions = obj.default_permissions - elif isinstance( obj, trans.app.model.Dataset ): - current_actions = obj.actions - else: - current_actions = obj.dataset.actions -%> - - - -
    -
    Associate with roles and set permissions
    -
    -
    - -
    -
    - %for k, v in trans.app.model.Dataset.permitted_actions.items(): + +
    +
    Associate with roles and set permissions on ${obj_str}
    +
    + + +
    + %for k, v in trans.app.model.Dataset.permitted_actions.items(): +
    + ${render_select( current_actions, k, v, all_roles )} +
    + %endfor
    - ${render_select( current_actions, k, v, all_roles )} +
    - %endfor -
    - -
    - + +
    -
    -

    - +

    diff --git a/templates/history/permissions.mako b/templates/history/permissions.mako index 6d119ab8e98..a189523440d 100644 --- a/templates/history/permissions.mako +++ b/templates/history/permissions.mako @@ -3,5 +3,5 @@ <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> %if trans.user: - ${render_permission_form( trans.history, h.url_for(), 'id', None, trans.user.all_roles() )} + ${render_permission_form( trans.history, trans.history.name, h.url_for(), 'id', None, trans.user.all_roles() )} %endif diff --git a/templates/user/permissions.mako b/templates/user/permissions.mako index 6e00a3f1a53..45b44795f38 100644 --- a/templates/user/permissions.mako +++ b/templates/user/permissions.mako @@ -3,5 +3,5 @@ <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> %if trans.user: - ${render_permission_form( trans.user, h.url_for(), 'id', None, trans.user.all_roles() )} + ${render_permission_form( trans.user, trans.user.email, h.url_for(), 'id', None, trans.user.all_roles() )} %endif diff --git a/test-data/library/3.bed b/test-data/library/3.bed new file mode 100644 index 00000000000..124167d1871 --- /dev/null +++ b/test-data/library/3.bed @@ -0,0 +1,25 @@ +chr1 147962006 147975713 NM_005997 0 - 147962192 147975670 0 6 574,145,177,115,153,160, 0,1543,7859,9048,9340,13547, +chr1 147984101 148035079 BC007833 0 + 147984545 148033414 0 14 529,32,81,131,118,153,300,206,84,49,85,130,46,1668, 0,25695,28767,33118,33695,33998,35644,38005,39629,40577,41402,43885,48367,49310, +chr1 148077485 148111797 NM_002651 0 - 148078400 148111728 0 12 1097,121,133,266,124,105,110,228,228,45,937,77, 0,2081,2472,6871,9907,10257,11604,14199,15637,18274,23636,34235, +chr1 148185113 148187485 NM_002796 0 + 148185136 148187378 0 7 163,207,147,82,117,89,120, 0,416,877,1199,1674,1977,2252, +chr2 118288484 118306183 NM_006773 0 + 118288583 118304530 0 14 184,285,144,136,101,200,115,140,162,153,114,57,178,1796, 0,2765,4970,6482,6971,7183,7468,9890,10261,10768,11590,14270,14610,15903, +chr2 118389378 118390700 BC005078 0 - 118390395 118390500 0 1 1322, 0, +chr2 220108603 220116964 NM_001927 0 + 220108689 220116217 0 9 664,61,96,162,126,221,44,83,789, 0,1718,1874,2118,2451,2963,5400,7286,7572, +chr2 220229182 220233943 NM_024536 0 - 220229609 220233765 0 4 1687,180,574,492, 0,1990,2660,4269, +chr5 131170738 131357870 AF099740 0 - 131311206 131357817 0 31 112,124,120,81,65,40,120,129,61,88,94,79,72,102,144,117,89,73,96,135,135,78,74,52,33,179,100,102,65,115,248, 0,11593,44117,47607,104668,109739,114675,126366,135488,137518,138009,140437,152389,153373,155388,159269,160793,162981,164403,165577,166119,167611,169501,178260,179675,180901,181658,182260,182953,183706,186884, +chr5 131424245 131426795 NM_000588 0 + 131424298 131426383 0 5 215,42,90,42,535, 0,313,1658,1872,2015, +chr5 131556201 131590458 NM_004199 0 - 131556601 131582218 0 15 471,97,69,66,54,100,71,177,194,240,138,152,97,100,170, 0,2316,2802,5596,6269,11138,11472,15098,16528,17674,21306,24587,25142,25935,34087, +chr5 131621285 131637046 NM_003687 0 + 131621326 131635821 0 7 134,152,82,179,164,118,1430, 0,4915,8770,13221,13609,14097,14331, +chr6 108298214 108386086 NM_007214 0 - 108299600 108385906 0 21 1530,105,99,102,159,174,60,83,148,155,93,133,95,109,51,59,62,113,115,100,304, 0,2490,6246,10831,12670,23164,23520,27331,31052,32526,34311,36130,36365,38609,41028,42398,43048,51479,54500,59097,87568, +chr6 108593954 108616704 NM_003269 0 + 108594662 108615360 0 9 733,146,88,236,147,97,150,106,1507, 0,5400,8778,10445,12037,14265,14749,15488,21243, +chr6 108639410 108689143 NM_152827 0 - 108640045 108688818 0 3 741,125,487, 0,2984,49246, +chr6 108722790 108950942 NM_145315 0 + 108722976 108950321 0 13 325,224,52,102,131,100,59,83,71,101,141,114,750, 0,28931,52094,60760,61796,71339,107102,152319,181970,182297,215317,224802,227402, +chr7 113320332 113924911 AK131266 0 + 113862563 113893433 0 20 285,91,178,90,58,75,138,51,201,178,214,105,88,84,77,102,122,70,164,1124, 0,201692,340175,448290,451999,484480,542213,543265,543478,545201,556083,558358,565876,567599,573029,573245,575738,577123,577946,603455, +chr7 116511232 116557294 NM_003391 0 - 116512159 116556994 0 5 1157,265,278,227,383, 0,20384,37843,43339,45679, +chr7 116713967 116902666 NM_000492 0 + 116714099 116901113 0 27 185,111,109,216,90,164,126,247,93,183,192,95,87,724,129,38,251,80,151,228,101,249,156,90,173,106,1754, 0,24290,29071,50936,54313,55285,56585,60137,62053,68678,79501,107776,110390,111971,114967,122863,123569,126711,130556,131618,134650,147559,162475,172879,184725,185496,186945, +chr7 116944658 117107512 AF377960 0 - 116945541 116979926 0 23 1129,102,133,64,186,206,179,188,153,100,87,80,96,276,118,255,151,100,204,1654,225,108,173, 0,7364,8850,10413,13893,14398,17435,24259,24615,35177,35359,45901,47221,49781,56405,66857,69787,72208,73597,80474,100111,150555,162681, +chr8 118880786 119193239 NM_000127 0 - 118881131 119192466 0 11 531,172,161,90,96,119,133,120,108,94,1735, 0,5355,7850,13505,19068,20309,23098,30863,36077,37741,310718, +chr9 128763240 128783870 NM_174933 0 + 128764156 128783586 0 12 261,118,74,159,76,48,56,63,129,117,127,370, 0,522,875,5630,12374,12603,15040,15175,18961,19191,20037,20260, +chr9 128787362 128789566 NM_014908 0 - 128787519 128789136 0 1 2204, 0, +chr9 128789530 128848928 NM_015354 0 + 128789552 128848511 0 44 54,55,74,85,81,45,93,120,212,115,201,90,66,120,127,153,127,88,77,115,121,67,129,140,107,207,170,70,68,196,78,86,146,182,201,93,159,138,75,228,132,74,130,594, 0,1491,5075,8652,9254,10312,11104,11317,20808,21702,23060,25462,31564,32908,33566,34851,35204,35595,35776,37202,38860,39111,39891,40349,42422,45499,45827,46675,47158,47621,50453,50840,51474,51926,53831,54186,55119,55619,57449,57605,57947,58352,58541,58804, +chr9 128849867 128870133 NM_020145 0 - 128850516 128869987 0 11 757,241,101,90,24,63,93,134,129,142,209, 0,1071,1736,2085,2635,4201,6376,6736,13056,14247,20057, diff --git a/test-data/library/4.bed b/test-data/library/4.bed new file mode 100644 index 00000000000..6f32a4fb5a3 --- /dev/null +++ b/test-data/library/4.bed @@ -0,0 +1 @@ +chr22 30128507 31828507 uc003bnx.1_cds_2_0_chr22_29227_f 0 + diff --git a/test-data/library/5.bed b/test-data/library/5.bed new file mode 100644 index 00000000000..646dca7a428 --- /dev/null +++ b/test-data/library/5.bed @@ -0,0 +1,134 @@ +chr7 115444712 115444739 CCDS5763.1_cds_0_0_chr7_115444713_f 0 + +chr7 115468538 115468624 CCDS5763.1_cds_1_0_chr7_115468539_f 0 + +chr7 115483024 115483277 CCDS5763.1_cds_2_0_chr7_115483025_f 0 + +chr7 115484165 115484501 CCDS5763.1_cds_3_0_chr7_115484166_f 0 + +chr7 115485764 115485980 CCDS5763.1_cds_4_0_chr7_115485765_f 0 + +chr7 115486322 115486481 CCDS5763.1_cds_5_0_chr7_115486323_f 0 + +chr7 115491298 115491487 CCDS5763.1_cds_6_0_chr7_115491299_f 0 + +chr7 115468538 115468624 CCDS5764.1_cds_0_0_chr7_115468539_f 0 + +chr7 115483024 115483277 CCDS5764.1_cds_1_0_chr7_115483025_f 0 + +chr7 115484165 115484501 CCDS5764.1_cds_2_0_chr7_115484166_f 0 + +chr7 115485764 115485980 CCDS5764.1_cds_3_0_chr7_115485765_f 0 + +chr7 115486322 115486481 CCDS5764.1_cds_4_0_chr7_115486323_f 0 + +chr7 115491298 115491487 CCDS5764.1_cds_5_0_chr7_115491299_f 0 + +chr7 115733786 115733936 CCDS5766.1_cds_0_0_chr7_115733787_f 0 + +chr7 115734264 115734452 CCDS5766.1_cds_1_0_chr7_115734265_f 0 + +chr7 115739975 115740126 CCDS5766.1_cds_2_0_chr7_115739976_f 0 + +chr7 115733786 115733936 CCDS5765.1_cds_0_0_chr7_115733787_f 0 + +chr7 115739975 115740164 CCDS5765.1_cds_1_0_chr7_115739976_f 0 + +chr7 115759067 115759097 CCDS5767.1_cds_0_0_chr7_115759068_f 0 + +chr7 115760529 115760694 CCDS5767.1_cds_1_0_chr7_115760530_f 0 + +chr7 115792950 115793292 CCDS5767.1_cds_2_0_chr7_115792951_f 0 + +chr7 116096616 116096655 CCDS5768.1_cds_0_0_chr7_116096617_f 0 + +chr7 116122131 116122195 CCDS5768.1_cds_1_0_chr7_116122132_f 0 + +chr7 116126998 116127050 CCDS5768.1_cds_2_0_chr7_116126999_f 0 + +chr7 116132776 116132840 CCDS5768.1_cds_3_0_chr7_116132777_f 0 + +chr7 116138181 116138388 CCDS5768.1_cds_4_0_chr7_116138182_f 0 + +chr7 116140267 116140347 CCDS5768.1_cds_5_0_chr7_116140268_f 0 + +chr7 116144237 116144316 CCDS5768.1_cds_6_0_chr7_116144238_f 0 + +chr7 116146073 116146145 CCDS5768.1_cds_7_0_chr7_116146074_f 0 + +chr7 116150064 116150127 CCDS5768.1_cds_8_0_chr7_116150065_f 0 + +chr7 116151731 116151872 CCDS5768.1_cds_9_0_chr7_116151732_f 0 + +chr7 116187545 116187696 CCDS5770.1_cds_0_0_chr7_116187546_f 0 + +chr7 116333766 116333849 CCDS5770.1_cds_1_0_chr7_116333767_f 0 + +chr7 116353565 116353725 CCDS5770.1_cds_2_0_chr7_116353566_f 0 + +chr7 116363797 116363852 CCDS5770.1_cds_3_0_chr7_116363798_f 0 + +chr7 116364495 116364611 CCDS5770.1_cds_4_0_chr7_116364496_f 0 + +chr7 116365889 116365965 CCDS5770.1_cds_5_0_chr7_116365890_f 0 + +chr7 116368128 116368197 CCDS5770.1_cds_6_0_chr7_116368129_f 0 + +chr7 116370085 116370240 CCDS5770.1_cds_7_0_chr7_116370086_f 0 + +chr7 116372439 116372537 CCDS5770.1_cds_8_0_chr7_116372440_f 0 + +chr7 116404866 116404981 CCDS5770.1_cds_9_0_chr7_116404867_f 0 + +chr7 116423325 116423398 CCDS5770.1_cds_10_0_chr7_116423326_f 0 + +chr7 116424838 116424941 CCDS5770.1_cds_11_0_chr7_116424839_f 0 + +chr7 116443791 116443942 CCDS5770.1_cds_12_0_chr7_116443792_f 0 + +chr7 116453088 116453181 CCDS5770.1_cds_13_0_chr7_116453089_f 0 + +chr7 116455927 116456067 CCDS5770.1_cds_14_0_chr7_116455928_f 0 + +chr7 116456865 116456985 CCDS5770.1_cds_15_0_chr7_116456866_f 0 + +chr7 116187545 116187696 CCDS5769.1_cds_0_0_chr7_116187546_f 0 + +chr7 116333766 116333849 CCDS5769.1_cds_1_0_chr7_116333767_f 0 + +chr7 116353565 116353725 CCDS5769.1_cds_2_0_chr7_116353566_f 0 + +chr7 116363797 116363852 CCDS5769.1_cds_3_0_chr7_116363798_f 0 + +chr7 116364495 116364611 CCDS5769.1_cds_4_0_chr7_116364496_f 0 + +chr7 116365889 116365965 CCDS5769.1_cds_5_0_chr7_116365890_f 0 + +chr7 116370085 116370240 CCDS5769.1_cds_6_0_chr7_116370086_f 0 + +chr7 116372439 116372537 CCDS5769.1_cds_7_0_chr7_116372440_f 0 + +chr7 116404866 116404981 CCDS5769.1_cds_8_0_chr7_116404867_f 0 + +chr7 116423325 116423398 CCDS5769.1_cds_9_0_chr7_116423326_f 0 + +chr7 116424838 116424941 CCDS5769.1_cds_10_0_chr7_116424839_f 0 + +chr7 116443791 116443942 CCDS5769.1_cds_11_0_chr7_116443792_f 0 + +chr7 116453088 116453181 CCDS5769.1_cds_12_0_chr7_116453089_f 0 + +chr7 116455927 116456067 CCDS5769.1_cds_13_0_chr7_116455928_f 0 + +chr7 116463766 116463862 CCDS5769.1_cds_14_0_chr7_116463767_f 0 + +chr7 116512159 116512389 CCDS5771.1_cds_0_0_chr7_116512160_r 0 - +chr7 116531616 116531881 CCDS5771.1_cds_1_0_chr7_116531617_r 0 - +chr7 116549075 116549353 CCDS5771.1_cds_2_0_chr7_116549076_r 0 - +chr7 116554571 116554798 CCDS5771.1_cds_3_0_chr7_116554572_r 0 - +chr7 116556911 116556994 CCDS5771.1_cds_4_0_chr7_116556912_r 0 - +chr7 116597600 116597753 CCDS5772.1_cds_0_0_chr7_116597601_r 0 - +chr7 116601356 116601470 CCDS5772.1_cds_1_0_chr7_116601357_r 0 - +chr7 116602616 116602722 CCDS5772.1_cds_2_0_chr7_116602617_r 0 - +chr7 116613942 116614052 CCDS5772.1_cds_3_0_chr7_116613943_r 0 - +chr7 116615015 116615072 CCDS5772.1_cds_4_0_chr7_116615016_r 0 - +chr7 116616073 116616149 CCDS5772.1_cds_5_0_chr7_116616074_r 0 - +chr7 116616990 116617115 CCDS5772.1_cds_6_0_chr7_116616991_r 0 - +chr7 116618730 116618865 CCDS5772.1_cds_7_0_chr7_116618731_r 0 - +chr7 116619702 116619814 CCDS5772.1_cds_8_0_chr7_116619703_r 0 - +chr7 116654167 116654279 CCDS5772.1_cds_9_0_chr7_116654168_r 0 - +chr7 116656241 116656364 CCDS5772.1_cds_10_0_chr7_116656242_r 0 - +chr7 116660840 116660940 CCDS5772.1_cds_11_0_chr7_116660841_r 0 - +chr7 116661360 116661465 CCDS5772.1_cds_12_0_chr7_116661361_r 0 - +chr7 116714099 116714152 CCDS5773.1_cds_0_0_chr7_116714100_f 0 + +chr7 116738257 116738368 CCDS5773.1_cds_1_0_chr7_116738258_f 0 + +chr7 116743038 116743147 CCDS5773.1_cds_2_0_chr7_116743039_f 0 + +chr7 116764903 116765119 CCDS5773.1_cds_3_0_chr7_116764904_f 0 + +chr7 116768280 116768370 CCDS5773.1_cds_4_0_chr7_116768281_f 0 + +chr7 116769252 116769416 CCDS5773.1_cds_5_0_chr7_116769253_f 0 + +chr7 116770552 116770678 CCDS5773.1_cds_6_0_chr7_116770553_f 0 + +chr7 116774104 116774351 CCDS5773.1_cds_7_0_chr7_116774105_f 0 + +chr7 116776020 116776113 CCDS5773.1_cds_8_0_chr7_116776021_f 0 + +chr7 116782645 116782828 CCDS5773.1_cds_9_0_chr7_116782646_f 0 + +chr7 116793468 116793660 CCDS5773.1_cds_10_0_chr7_116793469_f 0 + +chr7 116821743 116821838 CCDS5773.1_cds_11_0_chr7_116821744_f 0 + +chr7 116824357 116824444 CCDS5773.1_cds_12_0_chr7_116824358_f 0 + +chr7 116825938 116826662 CCDS5773.1_cds_13_0_chr7_116825939_f 0 + +chr7 116828934 116829063 CCDS5773.1_cds_14_0_chr7_116828935_f 0 + +chr7 116836830 116836868 CCDS5773.1_cds_15_0_chr7_116836831_f 0 + +chr7 116837536 116837787 CCDS5773.1_cds_16_0_chr7_116837537_f 0 + +chr7 116840678 116840758 CCDS5773.1_cds_17_0_chr7_116840679_f 0 + +chr7 116844523 116844674 CCDS5773.1_cds_18_0_chr7_116844524_f 0 + +chr7 116845585 116845813 CCDS5773.1_cds_19_0_chr7_116845586_f 0 + +chr7 116848617 116848718 CCDS5773.1_cds_20_0_chr7_116848618_f 0 + +chr7 116861526 116861775 CCDS5773.1_cds_21_0_chr7_116861527_f 0 + +chr7 116876442 116876598 CCDS5773.1_cds_22_0_chr7_116876443_f 0 + +chr7 116886846 116886936 CCDS5773.1_cds_23_0_chr7_116886847_f 0 + +chr7 116898692 116898865 CCDS5773.1_cds_24_0_chr7_116898693_f 0 + +chr7 116899463 116899569 CCDS5773.1_cds_25_0_chr7_116899464_f 0 + +chr7 116900912 116901113 CCDS5773.1_cds_26_0_chr7_116900913_f 0 + +chr7 116945541 116945787 CCDS5774.1_cds_0_0_chr7_116945542_r 0 - +chr7 116952022 116952124 CCDS5774.1_cds_1_0_chr7_116952023_r 0 - +chr7 116953508 116953641 CCDS5774.1_cds_2_0_chr7_116953509_r 0 - +chr7 116955071 116955135 CCDS5774.1_cds_3_0_chr7_116955072_r 0 - +chr7 116958551 116958737 CCDS5774.1_cds_4_0_chr7_116958552_r 0 - +chr7 116959056 116959262 CCDS5774.1_cds_5_0_chr7_116959057_r 0 - +chr7 116962093 116962272 CCDS5774.1_cds_6_0_chr7_116962094_r 0 - +chr7 116968917 116969105 CCDS5774.1_cds_7_0_chr7_116968918_r 0 - +chr7 116969273 116969426 CCDS5774.1_cds_8_0_chr7_116969274_r 0 - +chr7 116979835 116979935 CCDS5774.1_cds_9_0_chr7_116979836_r 0 - +chr7 116980017 116980104 CCDS5774.1_cds_10_0_chr7_116980018_r 0 - +chr7 116990559 116990639 CCDS5774.1_cds_11_0_chr7_116990560_r 0 - +chr7 116991879 116991975 CCDS5774.1_cds_12_0_chr7_116991880_r 0 - +chr7 116994439 116994715 CCDS5774.1_cds_13_0_chr7_116994440_r 0 - +chr7 117001063 117001181 CCDS5774.1_cds_14_0_chr7_117001064_r 0 - +chr7 117011515 117011770 CCDS5774.1_cds_15_0_chr7_117011516_r 0 - +chr7 117014445 117014596 CCDS5774.1_cds_16_0_chr7_117014446_r 0 - +chr7 117016866 117016966 CCDS5774.1_cds_17_0_chr7_117016867_r 0 - +chr7 117018255 117018459 CCDS5774.1_cds_18_0_chr7_117018256_r 0 - +chr7 117025132 117026786 CCDS5774.1_cds_19_0_chr7_117025133_r 0 - +chr7 117044769 117044994 CCDS5774.1_cds_20_0_chr7_117044770_r 0 - +chr7 117095213 117095321 CCDS5774.1_cds_21_0_chr7_117095214_r 0 - +chr7 117107339 117107420 CCDS5774.1_cds_22_0_chr7_117107340_r 0 - +chr5 131424298 131424460 CCDS4149.1_cds_0_0_chr5_131424299_f 0 + +chr5 131424558 131424600 CCDS4149.1_cds_1_0_chr5_131424559_f 0 + +chr5 131425903 131425993 CCDS4149.1_cds_2_0_chr5_131425904_f 0 + +chr5 131426117 131426159 CCDS4149.1_cds_3_0_chr5_131426118_f 0 + diff --git a/test/base/twilltestcase.py b/test/base/twilltestcase.py index 4123ec9a01a..f0f820023ab 100644 --- a/test/base/twilltestcase.py +++ b/test/base/twilltestcase.py @@ -562,6 +562,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "4", group_id ) # form field 4 is the check box named 'groups' tc.submit( "create_role_button" ) except AssertionError, err: + self.home() errmsg = 'Exception caught attempting to create role: %s' % str( err ) raise AssertionError( errmsg ) self.home() @@ -601,6 +602,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "3", role_id ) # form field 3 is the check box named 'roles' tc.submit( "create_group_button" ) except AssertionError, err: + self.home() errmsg = 'Exception caught attempting to create group: %s' % str( err ) raise AssertionError( errmsg ) self.home() @@ -616,6 +618,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "1", user_id ) # form field 1 is the check box named 'members' tc.submit( "group_members_edit_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to create group: %s' % str( err ) ) self.home() def associate_groups_with_role( self, role_id, group_ids=[] ): @@ -631,6 +634,7 @@ class TwillTestCase( unittest.TestCase ): tc.submit( "groups_add_button" ) tc.submit( "role_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to associated groups with a role: %s' % str( err ) ) except: pass @@ -667,6 +671,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "2", description ) # form field 1 is the field named name... tc.submit( "create_library_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to create library: %s' % str( err ) ) self.home() def rename_library( self, library_id, name='New Test Library Renamed', description='New Test Library Description Re-described' ): @@ -679,6 +684,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "description", description ) # form field 2 is the field named description... tc.submit( "rename_library_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to rename a library: %s' % str( err ) ) self.home() def add_folder( self, folder_id, name='New Test Folder', description='New Test Folder Description' ): @@ -691,6 +697,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "description", description ) # form field 2 is the field named description... tc.submit( "new_folder_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to create a new folder: %s' % str( err ) ) self.home() def rename_folder( self, folder_id, name='New Test Folder Renamed', description='New Test Folder Description Re-described' ): @@ -703,6 +710,7 @@ class TwillTestCase( unittest.TestCase ): tc.fv( "1", "description", description ) # form field 2 is the field named description... tc.submit( "rename_folder_button" ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to rename a library: %s' % str( err ) ) self.home() def add_dataset( self, filename, folder_id, extension='auto', dbkey='hg18', roles=[] ): @@ -719,9 +727,49 @@ class TwillTestCase( unittest.TestCase ): for role_id in roles: tc.fv( "1", "roles", role_id ) # form field 7 is the select list named out_groups, note the buttons... tc.submit( "new_dataset_button" ) + self.last_page() + self.check_page_for_string( '1 new datasets added to the library ( each is selected below )' ) except AssertionError, err: + self.home() raise AssertionError( 'Exception caught attempting to create add a dataset to a folder: %s' % str( err ) ) self.home() + def add_datasets_from_library_dir( self, folder_id, extension='auto', dbkey='hg18', roles=[] ): + """Add a directory of datasets to a folder""" + try: + self.visit_url( "%s/admin/dataset?folder_id=%s" % ( self.url, folder_id ) ) + self.last_page() + self.check_page_for_string( 'Create a new library dataset' ) + tc.fv( "1", "folder_id", folder_id ) + tc.fv( "1", "extension", extension ) + tc.fv( "1", "dbkey", dbkey ) + library_dir = "%s" % self.file_dir + tc.fv( "1", "server_dir", "library" ) + for role_id in roles: + tc.fv( "1", "roles", role_id ) + tc.submit( "new_dataset_button" ) + self.last_page() + self.check_page_for_string( '3 new datasets added to the library ( each is selected below )' ) + self.check_page_for_string( "3.bed" ) + self.check_page_for_string( "4.bed" ) + self.check_page_for_string( "5.bed" ) + tc.submit( "action_on_datasets_button" ) + self.last_page() + self.check_page_for_string( '( 3 of them )' ) + self.check_page_for_string( 'New Test Role' ) + self.check_page_for_string( 'Another Test Role' ) + tc.find( "update_roles" ) + # NOTE: we cannot submit the form because of a bug in twill ( it cannot handle select lists + # that include no option fields. Since the "manage permissions" and "edit metadata" select + # lists have no options ( no roles associated ), submitting the form will throw a + # ParseError: exception. Uncomment the following 3 lines + # when twill fixes this bug... + # tc.submit( "update_roles" ) + # self.last_page() + # self.check_page_for_string( 'Libraries' ) + except AssertionError, err: + self.home() + raise AssertionError( 'Exception caught attempting to create add a directory of datasets to a folder: %s' % str( err ) ) + self.home() def mark_library_deleted( self, library_id ): """Mark a library as deleted""" self.visit_url( "%s/admin/library?id=%s&delete=True" % ( self.url, library_id ) ) diff --git a/test/functional/__init__.py b/test/functional/__init__.py index 600279450e2..828bb247ef6 100644 --- a/test/functional/__init__.py +++ b/test/functional/__init__.py @@ -75,6 +75,7 @@ def setup(): log_destination = "stdout", use_heartbeat=False, admin_users = 'test@bx.psu.edu', + library_import_dir = galaxy_test_file_dir, global_conf= { "__file__": "universe_wsgi.ini.sample" } ) log.info( "Embedded Universe application started" ) diff --git a/test/functional/test_security_and_libraries.py b/test/functional/test_security_and_libraries.py index 1ec7c2544cb..4554d6ff93f 100644 --- a/test/functional/test_security_and_libraries.py +++ b/test/functional/test_security_and_libraries.py @@ -40,7 +40,7 @@ class TestHistory( TwillTestCase ): self.check_page_for_string( security_msg ) self.visit_url( "%s/admin/dataset" % self.url ) self.check_page_for_string( security_msg ) - def test_05_login_as_admin( self ): + def test_03_login_as_admin( self ): """Testing logging in as an admin user""" self.login( email='test@bx.psu.edu' ) #This is configured as our admin user self.visit_page( "admin" ) @@ -72,7 +72,7 @@ class TestHistory( TwillTestCase ): self.visit_page( "admin" ) self.check_page_for_string( security_msg ) self.logout() - def test_10_create_role( self ): + def test_06_create_role( self ): """Testing creating new non-private role with 2 members""" self.login( email=testuser1.email ) self.create_role( user_ids=[ str( testuser1.id ), str( testuser2.id ) ] ) @@ -80,14 +80,14 @@ class TestHistory( TwillTestCase ): # Get the role object for later tests global new_test_role new_test_role = galaxy.model.Role.filter( galaxy.model.Role.table.c.name==name ).first() - def test_15_create_group( self ): + def test_09_create_group( self ): """Testing creating new group with 2 members and 1 associated role""" name = 'New Test Group' self.create_group( name=name, user_ids=[ str( testuser1.id ), str( testuser2.id ) ], role_ids=[ str( new_test_role.id ) ] ) # Get the group object for later tests global new_test_group new_test_group = galaxy.model.Group.filter( galaxy.model.Group.table.c.name==name ).first() - def test_20_add_group_member( self ): + def test_12_add_group_member( self ): """Testing editing membership of an existing group""" name = 'Another Test Group' self.create_group( name=name ) @@ -97,7 +97,7 @@ class TestHistory( TwillTestCase ): self.add_group_members( str( another_test_group.id ), [ str( testuser3.id ) ] ) self.visit_url( "%s/admin/group_members_edit?group_id=%s" % ( self.url, str( another_test_group.id ) ) ) self.check_page_for_string( testuser3.email ) - def test_25_associate_groups_with_role( self ): + def test_15_associate_groups_with_role( self ): """Testing adding existing groups to an existing role""" # NOTE: To get this to work with twill, all select lists on the ~/admin/role page must contain at least # 1 option value or twill throws an exception, which is: ParseError: OPTION outside of SELECT @@ -115,7 +115,7 @@ class TestHistory( TwillTestCase ): self.associate_groups_with_role( str( another_test_role.id ), group_ids=[ str( new_test_group.id ) ] ) self.visit_page( 'admin/roles' ) self.check_page_for_string( new_test_group.name ) - def test_30_create_library( self ): + def test_18_create_library( self ): """Testing creating new library""" name = 'New Test Library' description = 'New Test Library Description' @@ -127,20 +127,20 @@ class TestHistory( TwillTestCase ): library = galaxy.model.Library.filter( and_( galaxy.model.Library.table.c.name==name, galaxy.model.Library.table.c.description==description, galaxy.model.Library.table.c.deleted==False ) ).first() - def test_35_rename_library( self ): + def test_21_rename_library( self ): """Testing renaming a library""" self.rename_library( str( library.id ), name='New Test Library Renamed', description='New Test Library Description Re-described' ) self.visit_page( 'admin/libraries' ) self.check_page_for_string( "New Test Library Renamed" ) # Rename it back to what it was originally self.rename_library( str( library.id ), name='New Test Library', description='New Test Library Description' ) - def test_40_rename_root_folder( self ): + def test_24_rename_root_folder( self ): """Testing renaming a library root folder""" folder = library.root_folder self.rename_folder( str( folder.id ), name='New Test Library Root Folder', description='New Test Library Root Folder Description' ) self.visit_page( 'admin/libraries' ) self.check_page_for_string( "New Test Library Root Folder" ) - def test_45_add_public_dataset_to_root_folder( self ): + def test_27_add_public_dataset_to_root_folder( self ): """Testing adding a public dataset to a library root folder""" folder = library.root_folder self.add_dataset( '1.bed', str( folder.id ), extension='bed', dbkey='hg18', roles=[] ) @@ -148,29 +148,38 @@ class TestHistory( TwillTestCase ): self.check_page_for_string( "1.bed" ) self.check_page_for_string( "bed" ) self.check_page_for_string( "hg18" ) - def test_50_add_new_folder( self ): + def test_30_add_new_folder( self ): """Testing adding a folder to a library root folder""" - folder = library.root_folder - self.add_folder( str( folder.id ), name='New Test Folder', description='New Test Folder Description' ) + root_folder = library.root_folder + name = 'New Test Folder' + description = 'New Test Folder Description' + self.add_folder( str( root_folder.id ), name=name, description=description ) + global new_test_folder + new_test_folder = galaxy.model.LibraryFolder.filter( and_( galaxy.model.LibraryFolder.table.c.parent_id==root_folder.id, + galaxy.model.LibraryFolder.table.c.name==name, + galaxy.model.LibraryFolder.table.c.description==description ) ).first() self.visit_page( 'admin/libraries' ) self.check_page_for_string( "New Test Folder" ) - def test_55_mark_group_deleted( self ): + def test_33_add_datasets_from_library_dir( self ): + """Testing adding dataset from library directory to sub-folder""" + self.add_datasets_from_library_dir( str( new_test_folder.id ), roles=[ str( new_test_role.id ) ] ) + def test_36_mark_group_deleted( self ): """Testing marking a group as deleted""" self.visit_page( "admin/groups" ) self.check_page_for_string( another_test_group.name ) self.mark_group_deleted( str( another_test_group.id ) ) - def test_60_undelete_group( self ): + def test_39_undelete_group( self ): """Testing undeleting a deleted group""" self.undelete_group( str( another_test_group.id ) ) - def test_65_mark_role_deleted( self ): + def test_42_mark_role_deleted( self ): """Testing marking a role as deleted""" self.visit_page( "admin/roles" ) self.check_page_for_string( another_test_role.name ) self.mark_role_deleted( str( another_test_role.id ) ) - def test_70_undelete_role( self ): + def test_45_undelete_role( self ): """Testing undeleting a deleted role""" self.undelete_role( str( another_test_role.id ) ) - def test_75_mark_library_deleted( self ): + def test_48_mark_library_deleted( self ): """Testing marking a library as deleted""" self.mark_library_deleted( str( library.id ) ) # Make sure the library was deleted @@ -179,19 +188,22 @@ class TestHistory( TwillTestCase ): raise AssertionError( 'The library id %s named "%s" has not been marked as deleted.' % ( str( library.id ), library.name ) ) def check_folder( library_folder ): for folder in library_folder.folders: + folder.refresh() # Make sure all of the library_folders are deleted if not folder.deleted: raise AssertionError( 'The library_folder named "%s" has not been marked as deleted ( library.id: %s ).' % ( folder.name, str( library.id ) ) ) check_folder( folder ) # Make sure all of the library_folder_dataset_associations are deleted for lfda in library_folder.datasets: + lfda.refresh() if not lfda.deleted: raise AssertionError( 'The library_folder_dataset_association id %s named "%s" has not been marked as deleted ( library.id: %s ).' % ( str( lfda.id ), lfda.name, str( library.id ) ) ) # Make sure none of the datasets have been deleted since that should occur only when the library is purged + lfda.dataset.refresh() if lfda.dataset.deleted: raise AssertionError( 'The dataset with id "%s" has been marked as deleted when it should not have been.' % lfda.dataset.id ) check_folder( library.root_folder ) - def test_80_mark_library_undeleted( self ): + def test_51_mark_library_undeleted( self ): """Testing marking a library as not deleted""" self.mark_library_undeleted( str( library.id ) ) # Make sure the library is undeleted @@ -220,7 +232,7 @@ class TestHistory( TwillTestCase ): library.refresh() if not library.deleted: raise AssertionError( 'The library id %s named "%s" has not been marked as deleted after it was undeleted.' % ( str( library.id ), library.name ) ) - def test_85_purge_group( self ): + def test_54_purge_group( self ): """Testing purging a group""" group_id = str( another_test_group.id ) self.purge_group( group_id ) @@ -232,7 +244,7 @@ class TestHistory( TwillTestCase ): gra = galaxy.model.GroupRoleAssociation.filter( galaxy.model.GroupRoleAssociation.table.c.group_id == group_id ).all() if gra: raise AssertionError( "Purging the group did not delete the GroupRoleAssociations for group_id '%s'" % group_id ) - def test_90_purge_role( self ): + def test_57_purge_role( self ): """Testing purging a role""" role_id = str( another_test_role.id ) self.purge_role( role_id ) @@ -244,7 +256,7 @@ class TestHistory( TwillTestCase ): adra = galaxy.model.ActionDatasetRoleAssociation.filter( galaxy.model.ActionDatasetRoleAssociation.table.c.role_id == role_id ).all() if adra: raise AssertionError( "Purging the role did not delete the ActionDatasetRoleAssociations for role_id '%s'" % role_id ) - def test_95_purge_library( self ): + def test_60_purge_library( self ): """Testing purging a library""" self.purge_library( str( library.id ) ) # Make sure the library was purged From 0a94eb20cd5b27e45318ae57c8099d491a0df5cc Mon Sep 17 00:00:00 2001 From: Greg Von Kuster Date: Wed, 19 Nov 2008 16:42:54 -0500 Subject: [PATCH 2/3] Fixes in security and libraries: standard messaging, more functional tests, better GUI flow, 2 new mappers, miscellaneous bug fixes. --- lib/galaxy/model/mapping.py | 8 +- lib/galaxy/web/controllers/admin.py | 365 +++++++++--------- .../dataset_security/deleted_groups.mako | 9 +- .../admin/dataset_security/deleted_roles.mako | 9 +- .../admin/dataset_security/group_create.mako | 8 +- .../dataset_security/group_members_edit.mako | 9 +- .../dataset_security/group_roles_edit.mako | 9 +- templates/admin/dataset_security/groups.mako | 9 +- templates/admin/dataset_security/index.mako | 13 - templates/admin/dataset_security/role.mako | 5 + .../admin/dataset_security/role_create.mako | 10 +- templates/admin/dataset_security/roles.mako | 9 +- templates/admin/dataset_security/user.mako | 7 +- .../dataset_security/user_groups_edit.mako | 9 +- templates/admin/dataset_security/users.mako | 9 +- .../library/add_dataset_from_history.mako | 20 +- templates/admin/library/browser.mako | 23 +- templates/admin/library/common.mako | 27 +- templates/admin/library/new_dataset.mako | 3 +- templates/admin/library/new_folder.mako | 3 +- templates/admin/library/new_library.mako | 3 +- templates/admin/library/rename_folder.mako | 3 +- templates/admin/library/rename_library.mako | 9 +- templates/admin/memdump.mako | 3 +- templates/admin/reload_tool.mako | 3 +- templates/base.mako | 20 +- templates/base_panels.mako | 56 +-- templates/library/browser.mako | 140 ++++--- templates/library/common.mako | 144 +++---- templates/message.mako | 55 +-- test/base/twilltestcase.py | 23 +- .../functional/test_security_and_libraries.py | 32 +- 32 files changed, 541 insertions(+), 514 deletions(-) delete mode 100644 templates/admin/dataset_security/index.mako diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py index d992300719c..4696c0ca1ad 100644 --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -391,7 +391,10 @@ assign_mapper( context, HistoryDatasetAssociation, HistoryDatasetAssociation.tab children=relation( HistoryDatasetAssociation, primaryjoin=( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ), - backref=backref( "parent", primaryjoin=( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ), remote_side=[HistoryDatasetAssociation.table.c.id], uselist=False ) ) + backref=backref( "parent", primaryjoin=( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ), remote_side=[HistoryDatasetAssociation.table.c.id], uselist=False ) ), + visible_children=relation( + HistoryDatasetAssociation, + primaryjoin=( ( HistoryDatasetAssociation.table.c.parent_id == HistoryDatasetAssociation.table.c.id ) & ( HistoryDatasetAssociation.table.c.visible == True ) ) ) ) ) assign_mapper( context, Dataset, Dataset.table, @@ -531,6 +534,9 @@ assign_mapper( context, LibraryFolderDatasetAssociation, LibraryFolderDatasetAss LibraryFolderDatasetAssociation, primaryjoin=( LibraryFolderDatasetAssociation.table.c.parent_id == LibraryFolderDatasetAssociation.table.c.id ), backref=backref( "parent", primaryjoin=( LibraryFolderDatasetAssociation.table.c.parent_id == LibraryFolderDatasetAssociation.table.c.id ), remote_side=[LibraryFolderDatasetAssociation.table.c.id] ) ), + visible_children=relation( + LibraryFolderDatasetAssociation, + primaryjoin=( ( LibraryFolderDatasetAssociation.table.c.parent_id == LibraryFolderDatasetAssociation.table.c.id ) & ( LibraryFolderDatasetAssociation.table.c.visible == True ) ) ), tags=relation( LibraryTagDatasetAssociation, primaryjoin=( LibraryFolderDatasetAssociation.table.c.id == LibraryTagDatasetAssociation.table.c.dataset_id ), diff --git a/lib/galaxy/web/controllers/admin.py b/lib/galaxy/web/controllers/admin.py index 5394848f080..f3ae60abc5a 100644 --- a/lib/galaxy/web/controllers/admin.py +++ b/lib/galaxy/web/controllers/admin.py @@ -32,7 +32,8 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg - return trans.fill_template( '/admin/index.mako', msg=msg ) + messagetype = params.get( 'messagetype', 'done' ) + return trans.fill_template( '/admin/index.mako', msg=msg, messagetype=messagetype ) @web.expose def center( self, trans, **kwd ): if not self.user_is_admin( trans ): @@ -44,7 +45,8 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg - return trans.fill_template( '/admin/reload_tool.mako', toolbox=self.app.toolbox, msg=msg ) + messagetype = params.get( 'messagetype', 'done' ) + return trans.fill_template( '/admin/reload_tool.mako', toolbox=self.app.toolbox, msg=msg, messagetype=messagetype ) @web.expose def tool_reload( self, trans, tool_version=None, **kwd ): if not self.user_is_admin( trans ): @@ -53,7 +55,7 @@ class Admin( BaseController ): tool_id = params.tool_id self.app.toolbox.reload( tool_id ) msg = 'Reloaded tool: ' + tool_id - return trans.fill_template( '/admin/reload_tool.mako', toolbox=self.app.toolbox, msg=msg ) + return trans.fill_template( '/admin/reload_tool.mako', toolbox=self.app.toolbox, msg=msg, messagetype='done' ) # Galaxy Role Stuff @web.expose @@ -62,17 +64,20 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) return trans.fill_template( '/admin/dataset_security/roles.mako', roles=trans.app.model.Role.query() \ .filter( trans.app.model.Role.table.c.type != trans.app.model.Role.types.PRIVATE ) \ .order_by( trans.app.model.Role.table.c.name ).all(), - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def create_role( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) users=trans.app.model.User.query().order_by( trans.app.model.User.table.c.email ).all() groups = trans.app.model.Group.query() \ .filter( galaxy.model.Group.table.c.deleted==False ) \ @@ -81,21 +86,21 @@ class Admin( BaseController ): return trans.fill_template( '/admin/dataset_security/role_create.mako', users=users, groups=groups, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def new_role( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg name = params.name description = params.description if not name or not description: msg = "Please enter a name and a description" - trans.response.send_redirect( '/admin/create_role?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='create_role', msg=msg, messagetype='error' ) ) elif trans.app.model.Role.filter_by( name=name ).first(): msg = "A role with that name already exists" - trans.response.send_redirect( '/admin/create_role?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='create_role', msg=msg, messagetype='error' ) ) else: # Create the role role = galaxy.model.Role( name=name, @@ -117,13 +122,14 @@ class Admin( BaseController ): gra = galaxy.model.GroupRoleAssociation( group, role ) gra.flush() msg = "The new role has been created with %s associated users and %s associated groups" % ( str( len( users ) ), str( len( groups ) ) ) - trans.response.send_redirect( '/admin/roles?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose def role( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) role = trans.app.model.Role.get( int( params.role_id ) ) in_users = [] out_users = [] @@ -171,13 +177,13 @@ class Admin( BaseController ): in_groups=in_groups, out_groups=out_groups, library_dataset_actions=library_dataset_actions, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def role_members_edit( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg role = galaxy.model.Role.get( int( params.role_id ) ) in_users = [ trans.app.model.User.get( x ) for x in listify( params.in_users ) ] for ura in role.users: @@ -198,24 +204,24 @@ class Admin( BaseController ): trans.app.security_agent.set_entity_role_associations( roles=[ role ], users=in_users, groups=in_groups ) role.refresh() msg = "The role has been updated with %s associated users and %s associated groups" % ( str( len( in_users ) ), str( len( in_groups ) ) ) - trans.response.send_redirect( '/admin/roles?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose def mark_role_deleted( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg role = galaxy.model.Role.get( int( params.role_id ) ) role.deleted = True role.flush() msg = "The role has been marked as deleted." - trans.response.send_redirect( '/admin/roles?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose def deleted_roles( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) # Build a list of tuples which are roles followed by lists of groups and users # [ ( role, [ group, group, group ], [ user, user ] ), ( role, [ group, group ], [ user ] ) ] roles_groups_users = [] @@ -233,24 +239,23 @@ class Admin( BaseController ): roles_groups_users.append( ( role, groups, users ) ) return trans.fill_template( '/admin/dataset_security/deleted_roles.mako', roles_groups_users=roles_groups_users, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def undelete_role( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg role = galaxy.model.Role.get( int( params.role_id ) ) role.deleted = False role.flush() msg = "The role has been marked as not deleted." - trans.response.send_redirect( '/admin/roles?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose def purge_role( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg role = galaxy.model.Role.get( int( params.role_id ) ) # Delete UserRoleAssociations for ura in role.users: @@ -276,7 +281,7 @@ class Admin( BaseController ): role.delete() role.flush() msg = "The role has been purged from the database." - trans.response.send_redirect( '/admin/deleted_roles?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='deleted_roles', msg=msg, messagetype='done' ) ) # Galaxy Group Stuff @web.expose @@ -285,6 +290,7 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) # Build a list of tuples which are groups followed by lists of members and roles # [ ( group, [ member, member, member ], [ role, role ] ), ( group, [ member, member ], [ role ] ) ] groups_members_roles = [] @@ -302,13 +308,15 @@ class Admin( BaseController ): groups_members_roles.append( ( group, members, roles ) ) return trans.fill_template( '/admin/dataset_security/groups.mako', groups_members_roles=groups_members_roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def create_group( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) users=trans.app.model.User.query().order_by( trans.app.model.User.table.c.email ).all() roles = trans.app.model.Role.query() \ .filter( and_( galaxy.model.Role.table.c.deleted == False, @@ -318,20 +326,20 @@ class Admin( BaseController ): return trans.fill_template( '/admin/dataset_security/group_create.mako', users=users, roles=roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def new_group( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg name = params.name if not name: msg = "Please enter a name" - trans.response.send_redirect( '/admin/create_group?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='create_group', msg=msg, messagetype='error' ) ) elif trans.app.model.Group.filter_by( name=name ).first(): msg = "A group with that name already exists" - trans.response.send_redirect( '/admin/create_group?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='create_group', msg=msg, messagetype='error' ) ) else: # Create the group group = galaxy.model.Group( name ) @@ -355,13 +363,14 @@ class Admin( BaseController ): gra = galaxy.model.GroupRoleAssociation( group, role ) gra.flush() msg = "The new group has been created with %s members and %s associated roles" % ( str( len( members ) ), str( len( roles ) ) ) - trans.response.send_redirect( '/admin/groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose def group_members_edit( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) group = galaxy.model.Group.get( int( params.group_id ) ) members = [] for uga in group.members: @@ -370,7 +379,8 @@ class Admin( BaseController ): group=group, members=members, users=galaxy.model.User.query().order_by( galaxy.model.User.table.c.email ).all(), - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def update_group_members( self, trans, **kwd ): if not self.user_is_admin( trans ): @@ -397,7 +407,7 @@ class Admin( BaseController ): uga = galaxy.model.UserGroupAssociation( user, group ) uga.flush() msg = "Group membership has been updated with a total of %s members" % len( members ) - trans.response.send_redirect( '/admin/groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) # TODO: We probably don't want the following 2 methods since managing roles should be # restricted to the Role page due to private roles and rules governing them @web.expose @@ -406,6 +416,7 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) group = galaxy.model.Group.get( int( params.group_id ) ) group_roles = [] for gra in group.roles: @@ -414,7 +425,8 @@ class Admin( BaseController ): group=group, group_roles=group_roles, roles=galaxy.model.Role.query().order_by( galaxy.model.Role.table.c.name ).all(), - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def update_group_roles( self, trans, **kwd ): if not self.user_is_admin( trans ): @@ -441,24 +453,24 @@ class Admin( BaseController ): gra = galaxy.model.GroupRoleAssociation( group, role ) gra.flush() msg = "Group updated with a total of %s associated roles" % len( roles ) - trans.response.send_redirect( '/admin/groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose def mark_group_deleted( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg group = galaxy.model.Group.get( int( params.group_id ) ) group.deleted = True group.flush() msg = "The group has been marked as deleted." - trans.response.send_redirect( '/admin/groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose def deleted_groups( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) # Build a list of tuples which are groups followed by lists of members and roles # [ ( group, [ member, member, member ], [ role, role ] ), ( group, [ member, member ], [ role ] ) ] groups_members_roles = [] @@ -476,24 +488,23 @@ class Admin( BaseController ): groups_members_roles.append( ( group, members, roles ) ) return trans.fill_template( '/admin/dataset_security/deleted_groups.mako', groups_members_roles=groups_members_roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def undelete_group( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg group = galaxy.model.Group.get( int( params.group_id ) ) group.deleted = False group.flush() msg = "The group has been marked as not deleted." - trans.response.send_redirect( '/admin/groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose def purge_group( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg group = galaxy.model.Group.get( int( params.group_id ) ) # Delete UserGroupAssociations for uga in group.users: @@ -507,7 +518,7 @@ class Admin( BaseController ): group.delete() group.flush() msg = "The group has been purged from the database." - trans.response.send_redirect( '/admin/deleted_groups?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='deleted_groups', msg=msg, messagetype='done' ) ) # Galaxy User Stuff @web.expose @@ -516,6 +527,7 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) # Build a list of tuples which are users followed by lists of groups and roles # [ ( user, [ group, group, group ], [ role, role ] ), ( user, [ group, group ], [ role ] ) ] users_groups_roles = [] @@ -530,7 +542,8 @@ class Admin( BaseController ): users_groups_roles.append( ( user, groups, roles ) ) return trans.fill_template( '/admin/dataset_security/users.mako', users_groups_roles=users_groups_roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def user( self, trans, **kwd ): if not self.user_is_admin( trans ): @@ -538,6 +551,7 @@ class Admin( BaseController ): params = util.Params( kwd ) user_id = params.user_id msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) user = trans.app.model.User.get( user_id ) # Get the groups and roles to which the user belongs groups = trans.app.model.Group.query() \ @@ -551,13 +565,15 @@ class Admin( BaseController ): user=user, groups=groups, roles=roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def user_groups_edit( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) user = galaxy.model.User.get( int( params.user_id ) ) user_groups = [] for uga in user.groups: @@ -570,7 +586,8 @@ class Admin( BaseController ): user=user, user_groups=user_groups, groups=groups, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def update_user_groups( self, trans, **kwd ): if not self.user_is_admin( trans ): @@ -592,7 +609,7 @@ class Admin( BaseController ): uga = galaxy.model.UserGroupAssociation( user, group ) uga.flush() msg = "The user now belongs to a total of %s groups" % len( groups ) - trans.response.send_redirect( '/admin/users?msg=%s' % msg ) + trans.response.send_redirect( web.url_for( action='users', msg=msg, messagetype='done' ) ) # Galaxy Library Stuff @web.expose @@ -601,13 +618,15 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) created_lfda_ids = params.get( 'created_lfda_ids', '' ) return trans.fill_template( '/admin/library/browser.mako', libraries=trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \ .order_by( trans.app.model.Library.name ).all(), created_lfda_ids=created_lfda_ids, deleted=False, - msg=msg ) + msg=msg, + messagetype=messagetype ) libraries = library_browser @web.expose def library( self, trans, id=None, **kwd ): @@ -615,6 +634,7 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) if params.get( 'new', False ): action = 'new' elif params.get( 'rename', False ): @@ -622,11 +642,11 @@ class Admin( BaseController ): elif params.get( 'delete', False ): action = 'delete' else: - msg = "You must specify a valid action ( new, rename, delete ) to perform on a library." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + msg = 'Invalid action attempted on library' + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) if not id and not action == 'new': msg = "You must specify a library to %s." % action - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) if not action == 'new': library = trans.app.model.Library.get( int( id ) ) if action == 'new': @@ -637,19 +657,27 @@ class Admin( BaseController ): root_folder.flush() library.root_folder = root_folder library.flush() - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - return trans.fill_template( '/admin/library/new_library.mako', msg=msg ) + msg = 'The new library named %s has been created' % library.name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) + return trans.fill_template( '/admin/library/new_library.mako', msg=msg, messagetype=messagetype ) elif action == 'rename': if params.rename == 'submitted': - if params.get( 'root_folder', None ): - root_folder = library.root_folder - root_folder.name = util.restore_text( params.name ) - root_folder.flush() - library.name = util.restore_text( params.name ) - library.description = util.restore_text( params.description ) - library.flush() - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - return trans.fill_template( '/admin/library/rename_library.mako', library=library, msg=msg ) + new_name = util.restore_text( params.name ) + new_description = util.restore_text( params.description ) + if not new_name: + msg = 'Enter a valid name' + return trans.fill_template( '/admin/library/rename_library.mako', library=library, msg=msg, messagetype='error' ) + else: + if params.get( 'root_folder', False ): + root_folder = library.root_folder + root_folder.name = new_name + root_folder.flush() + library.name = new_name + library.description = new_description + library.flush() + msg = 'The library has been renamed to %s' % new_name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) + return trans.fill_template( '/admin/library/rename_library.mako', library=library, msg=msg, messagetype=messagetype ) elif action == 'delete': def delete_folder( library_folder ): for folder in library_folder.active_folders: @@ -667,26 +695,27 @@ class Admin( BaseController ): library.deleted = True library.flush() msg = 'The library and all of its contents have been marked deleted' - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose def deleted_libraries( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) libraries=trans.app.model.Library.filter( and_( trans.app.model.Library.table.c.deleted==True, trans.app.model.Library.table.c.purged==False ) ) \ .order_by( trans.app.model.Library.table.c.name ).all() return trans.fill_template( '/admin/library/browser.mako', libraries=libraries, deleted=True, - msg=msg ) + msg=msg, + messagetype=messagetype ) @web.expose def undelete_library( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg library = galaxy.model.Library.get( int( params.id ) ) def undelete_folder( library_folder ): for folder in library_folder.folders: @@ -700,13 +729,12 @@ class Admin( BaseController ): library.deleted = False library.flush() msg = "The library and all of its contents have been marked not deleted" - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose def purge_library( self, trans, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) - msg = params.msg library = galaxy.model.Library.get( int( params.id ) ) def purge_folder( library_folder ): for lf in library_folder.folders: @@ -729,13 +757,14 @@ class Admin( BaseController ): library.purged = True library.flush() msg = "The library and all of its contents have been purged, datasets will be removed from disk via the cleanup_datasets script" - return trans.response.send_redirect( web.url_for( action='deleted_libraries', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='deleted_libraries', msg=msg, messagetype='done' ) ) @web.expose def folder( self, trans, id, **kwd ): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) if params.get( 'new', False ): action = 'new' elif params.get( 'rename', False ): @@ -743,12 +772,12 @@ class Admin( BaseController ): elif params.get( 'delete', False ): action = 'delete' else: - msg = "You must specify a valid action ( new, rename, delete ) to perform on a folder." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + msg = "Invalid action attempted on folder." + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) folder = trans.app.model.LibraryFolder.get( id ) if not folder: msg = "Invalid folder specified, id: %s" % str( id ) - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) if action == 'new': if params.new == 'submitted': new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ), @@ -759,17 +788,26 @@ class Admin( BaseController ): new_folder.genome_build = util.dbnames.default_value folder.add_folder( new_folder ) new_folder.flush() - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - return trans.fill_template( '/admin/library/new_folder.mako', folder=folder, msg=msg ) + msg = 'The new folder named %s has been added to this library' % new_folder.name + return trans.response.send_redirect( web.url_for( action='folder', id=new_folder.id, msg=msg, messagetype='done' ) ) + return trans.fill_template( '/admin/library/new_folder.mako', folder=folder, msg=msg, messagetype=messagetype ) elif action == 'rename': if params.rename == 'submitted': - folder.name = util.restore_text( params.name ) - folder.description = util.restore_text( params.description ) - folder.flush() - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - return trans.fill_template( '/admin/library/rename_folder.mako', folder=folder, msg=msg ) + new_name = util.restore_text( params.name ) + new_description = util.restore_text( params.description ) + if not new_name: + msg = 'Enter a valid name' + return trans.fill_template( '/admin/library/rename_folder.mako', folder=folder, msg=msg, messagetype='error' ) + else: + folder.name = new_name + folder.description = new_description + folder.flush() + msg = 'The folder has been renamed to %s' % new_name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) + return trans.fill_template( '/admin/library/rename_folder.mako', folder=folder, msg=msg, messagetype=messagetype ) elif action == 'delete': def delete_folder( folder ): + folder.refresh() for subfolder in folder.active_folders: delete_folder( subfolder ) for lfda in folder.active_datasets: @@ -778,8 +816,8 @@ class Admin( BaseController ): folder.deleted = True folder.flush() delete_folder( folder ) - msg = 'The folder and all of its contents have been marked deleted' - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + msg = 'The folder %s and all of its contents have been marked deleted' % folder.name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose def dataset( self, trans, id=None, name="Unnamed", info='no info', extension=None, folder_id=None, dbkey=None, **kwd ): if not self.user_is_admin( trans ): @@ -794,6 +832,7 @@ class Admin( BaseController ): data_files = [] params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) # add_file method def add_file( file_obj, name, extension, dbkey, last_used_build, roles, info='no info', space_to_tab=False ): @@ -874,7 +913,7 @@ class Admin( BaseController ): msg = 'Select a file, enter a URL or Text, or select a server directory.' else: msg = 'Select a file, enter a URL or enter Text.' - trans.response.send_redirect( web.url_for( action='dataset', folder_id=folder_id, msg=msg ) ) + trans.response.send_redirect( web.url_for( action='dataset', folder_id=folder_id, msg=msg, messagetype='done' ) ) space_to_tab = params.get( 'space_to_tab', False ) if space_to_tab and space_to_tab not in [ "None", None ]: space_to_tab = True @@ -953,10 +992,10 @@ class Admin( BaseController ): created_lfda_ids = created_lfda_ids.lstrip( ',' ) total_added = len( created_lfda_ids.split( ',' ) ) msg = "%i new datasets added to the library ( each is selected below ). Click the Go button at the bottom of this page to edit the permissions on these datasets." % total_added - trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg, messagetype='done' ) ) else: msg = "Upload failed" - trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', created_lfda_ids=created_lfda_ids, msg=msg, messagetype='error' ) ) # No dataset(s) specified, display upload form elif not id: @@ -975,7 +1014,8 @@ class Admin( BaseController ): dbkeys=dbkeys, last_used_build=last_used_build, roles=roles, - msg=msg ) + msg=msg, + messagetype=messagetype ) else: if id.count( ',' ): ids = id.split( ',' ) @@ -987,7 +1027,7 @@ class Admin( BaseController ): lda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) if not lda: msg = "Invalid dataset specified, id: %s" %str( id ) - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) # Copied from edit attributes for 'regular' datasets with some additions p = util.Params(kwd, safe=False) @@ -1021,7 +1061,8 @@ class Admin( BaseController ): lda.metadata.dbkey = dbkey lda.datatype.after_edit( lda ) trans.app.model.flush() - return trans.show_ok_message( "Attributes updated" ) + msg = 'Attributes updated for dataset %s' % lda.name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) elif p.detect: # The user clicked the Auto-detect button on the 'Edit Attributes' form for name, spec in lda.datatype.metadata_spec.items(): @@ -1032,11 +1073,14 @@ class Admin( BaseController ): lda.datatype.set_meta( lda ) lda.datatype.after_edit( lda ) trans.app.model.flush() - return trans.show_ok_message( "Attributes updated" ) + msg = 'Attributes updated for dataset %s' % lda.name + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) elif p.delete: + # The user selected the "Remove this dataset from the library" pop-up menu option lda.deleted = True lda.flush() - trans.response.send_redirect( web.url_for( action='library_browser' ) ) + msg = 'Dataset %s has been removed from this library' % lda.name + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) lda.datatype.before_edit( lda ) if "dbkey" in lda.datatype.metadata_spec and not lda.metadata.dbkey: # Copy dbkey into metadata, for backwards compatability @@ -1053,7 +1097,8 @@ class Admin( BaseController ): dataset=lda, datatypes=ldatatypes, err=None, - msg=msg ) + msg=msg, + messagetype=messagetype ) # multiple ids specfied, display permission form for each one... elif ids: lfdas = [] @@ -1061,11 +1106,11 @@ class Admin( BaseController ): lfda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) if lfda is None: msg = 'You specified an invalid dataset id: %s' %str( id ) - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) lfdas.append( lfda ) if len( lfdas ) < 2: msg = 'You must specify at least two datasets on which to modify permissions, ids you sent: %s' % str( ids ) - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) if 'update_roles' in kwd: #p = util.Params( kwd ) permissions = {} @@ -1076,7 +1121,7 @@ class Admin( BaseController ): trans.app.security_agent.set_dataset_permissions( lfda.dataset, permissions ) lfda.dataset.refresh() msg = 'Permissions and roles have been updated on %d datasets' % len( lfdas ) - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) # Ensure that the permissions across all datasets are identical. Otherwise, we can't update together. tmp = [] for lfda in lfdas: @@ -1085,40 +1130,49 @@ class Admin( BaseController ): tmp.append( perms ) if len( tmp ) != 1: msg = 'The datasets you selected do not have identical permissions, so they can not be updated together' - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) else: return trans.fill_template( "/admin/library/dataset.mako", dataset=lfdas ) @web.expose def add_dataset_to_folder_from_history( self, trans, ids="", folder_id=None, **kwd ): - if not isinstance( ids, list ): - if ids: - ids = ids.split( "," ) - else: - ids = [] + if not self.user_is_admin( trans ): + return trans.show_error_message( no_privilege_msg ) try: folder = trans.app.model.LibraryFolder.get( folder_id ) except: - folder = None - if folder is None: - msg = "You must provide a valid target folder." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - error_msg = ok_msg = "" - dataset_names = [] - if ids: - for data_id in ids: - data = trans.app.model.HistoryDatasetAssociation.get( data_id ) - if data: - data.to_library_dataset_folder_association( target_folder = folder ) - dataset_names.append( data.name ) + msg = "Invalid folder id: %s" % str( folder_id ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) + params = util.Params( kwd ) + msg = params.get( 'msg', None ) + messagetype = params.get( 'messagetype', 'done' ) + # See if the current history is empty + history=trans.get_history() + if not history.active_datasets: + msg = 'Your current history is empty' + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) + if params.get( 'add_dataset_from_history_button', False ): + if not isinstance( ids, list ): + if ids: + ids = ids.split( "," ) else: - error_msg += "A requested dataset (%s) was invalid. " % ( data_id ) - if dataset_names: - ok_msg = "Added datasets (%s) to the library folder." % ( ", ".join( dataset_names ) ) - return trans.fill_template( "/admin/library/add_dataset_from_history.mako", - history=trans.get_history(), - folder=folder, - ok_msg=ok_msg, - error_msg=error_msg ) + ids = [] + dataset_names = [] + if ids: + for data_id in ids: + data = trans.app.model.HistoryDatasetAssociation.get( data_id ) + if data: + data.to_library_dataset_folder_association( target_folder = folder ) + dataset_names.append( data.name ) + else: + msg = "The requested dataset id '%s' is invalid" % str( data_id ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) + if dataset_names: + msg = "Added the following datasets to the library folder: %s" % ( ", ".join( dataset_names ) ) + return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) + else: + msg = 'Select at least one dataset from the list' + messagetype = 'error' + return trans.fill_template( "/admin/library/add_dataset_from_history.mako", history=history, folder=folder, msg=msg, messagetype=messagetype ) def check_gzip( self, temp_name ): """ @@ -1143,98 +1197,45 @@ class Admin( BaseController ): return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg + messagetype = params.get( 'messagetype', 'done' ) if params.get( 'action_on_datasets_button', False ): if not params.dataset_ids: msg = "At least one dataset must be selected for %s" % params.action - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) dataset_ids = listify( params.dataset_ids ) if params.action == 'edit': - trans.response.send_redirect( web.url_for( action='dataset', id=",".join( dataset_ids ) ) ) + trans.response.send_redirect( web.url_for( action='dataset', id=",".join( dataset_ids ), msg=msg, messagetype=messagetype ) ) elif params.action == 'delete': for id in dataset_ids: lfda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) lfda.deleted = True lfda.flush() msg = "The selected datasets have been removed from this library" - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) else: msg = "Action '%s' is not yet implemented" % str( params.action ) - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) else: - trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype=messagetype ) ) @web.expose def delete_dataset( self, trans, id=None, **kwd): if not self.user_is_admin( trans ): return trans.show_error_message( no_privilege_msg ) if id: # id is a LibraryFolderDatasetAssociation.id - library_folder_dataset_assoc = trans.app.model.LibraryFolderDatasetAssociation.get( id ) - self._delete_dataset( library_folder_dataset_assoc ) - trans.log_event( "Dataset id %s deleted from library folder id %s" % ( str( id ), str( library_folder_dataset_assoc.folder.id ) ) ) - trans.response.send_redirect( web.url_for( action = 'folder', id = library_folder_dataset_assoc.folder.id, msg = 'The dataset was deleted from the folder' ) ) + lfda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) + lfda.deleted = True + lfda.flush() + msg = "Dataset %s was deleted from library folder %s" % ( lfda.name, lfda.folder.name ) + trans.response.send_redirect( web.url_for( action='folder', + id=str( lfda.folder.id ), + msg=msg, + messagetype='done' ) ) msg = "You did not specify a dataset to delete." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - - def _delete_dataset( self, library_folder_dataset_assoc ): - #dataset = library_folder_dataset_assoc.dataset - # TODO: assuming 1 to 1 mapping between Dataset -> LibraryFolders ( i.e., is can the same - # dataset record be shared across LibraryFolders? - # Confirm that things should be deleted as follows - - ### Deleting the base dataset will delete datasets that exist in user's histories - ### ( LDA.dataset == HDA.dataset ) - ### Shouldn't this be a separate option? - ### For Now, I am commenting out logic that acts on the dataset directly - ### -- Dan: - - - # Delete the LibraryFolderDatasetAssociation - library_folder_dataset_assoc.deleted = True - library_folder_dataset_assoc.flush() - - @web.expose - def delete_folder( self, trans, id=None, **kwd): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) - if id: - if 'confirm' not in kwd: - return trans.show_warn_message( 'Click here to confirm folder deletion.' % web.url_for( action = 'delete_folder', id = id, confirm=True ) ) - # id is a LibraryFolder.id - folder = trans.app.model.LibraryFolder.get( id ) - self._delete_folder( folder ) - - trans.log_event( "Folder id %s deleted." % id ) - - if folder.library_root: - trans.response.send_redirect( web.url_for( action = 'library', id = folder.library_root[0].id, msg = 'You have deleted the root folder.' ) ) - trans.response.send_redirect( web.url_for( action = 'folder', id = folder.parent_id, msg = 'The folder was deleted.' ) ) - msg = "You did not specify a folder to delete." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) - - def _delete_folder( self, folder ): - for lfda in folder.active_datasets: - self._delete_dataset( lfda ) - for folder in folder.active_folders: - self._delete_folder( folder ) - folder.deleted = True - folder.flush() - - @web.expose - def delete_library( self, trans, id=None, **kwd): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) - if id: - if 'confirm' not in kwd: - return trans.show_warn_message( 'Click here to confirm library deletion.' % web.url_for( action = 'delete_library', id = id, confirm=True ) ) - # id is a LibraryFolder.id - library = trans.app.model.Library.get( id ) - self._delete_folder( library.root_folder ) - library.deleted = True - library.flush() - trans.log_event( "Library id %s deleted." % id ) - trans.response.send_redirect( web.url_for( action = 'libraries', msg = 'You have deleted the library %s.' % library.id ) ) - msg = "You did not specify a library to delete." - return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg ) ) + return trans.response.send_redirect( web.url_for( action='folder', + id=str( lfda.folder.id ), + msg=msg, + messagetype='error' ) ) @web.expose def memdump( self, trans, ids = 'None', sorts = 'None', pages = 'None', new_id = None, new_sort = None, **kwd ): diff --git a/templates/admin/dataset_security/deleted_groups.mako b/templates/admin/dataset_security/deleted_groups.mako index 446cb58a336..422c80073bd 100644 --- a/templates/admin/dataset_security/deleted_groups.mako +++ b/templates/admin/dataset_security/deleted_groups.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a row <%def name="render_row( group, members, roles, ctr, anchored, curr_anchor )"> @@ -36,12 +37,12 @@ -%if msg: -

    ${msg}
    -%endif -

    Deleted Groups

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( groups_members_roles ) == 0: There are no deleted Galaxy groups %else: diff --git a/templates/admin/dataset_security/deleted_roles.mako b/templates/admin/dataset_security/deleted_roles.mako index 8f3803d4930..9975997d92e 100644 --- a/templates/admin/dataset_security/deleted_roles.mako +++ b/templates/admin/dataset_security/deleted_roles.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a row <%def name="render_row( role, groups, users, ctr, anchored, curr_anchor )"> @@ -36,12 +37,12 @@ -%if msg: -
    ${msg}
    -%endif -

    Deleted Roles

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( roles_groups_users ) == 0: There are no deleted Galaxy roles %else: diff --git a/templates/admin/dataset_security/group_create.mako b/templates/admin/dataset_security/group_create.mako index 50aca838830..a137eb33ebb 100644 --- a/templates/admin/dataset_security/group_create.mako +++ b/templates/admin/dataset_security/group_create.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a user row <%def name="render_user_row( user, ctr )"> @@ -29,12 +30,11 @@ -%if msg: -
    ${msg}
    -%endif -

    Create Group

    +%if msg: + ${render_msg( msg, messagetype )} +%endif
    diff --git a/templates/admin/dataset_security/group_members_edit.mako b/templates/admin/dataset_security/group_members_edit.mako index a7f8f5223ca..eb669d0c125 100644 --- a/templates/admin/dataset_security/group_members_edit.mako +++ b/templates/admin/dataset_security/group_members_edit.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a row <%def name="render_row( user, ctr, anchored, curr_anchor, check )"> @@ -17,12 +18,12 @@ -%if msg: -
    ${msg}
    -%endif -

    Members of group '${group.name}'

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( users ) == 0: %else: diff --git a/templates/admin/dataset_security/group_roles_edit.mako b/templates/admin/dataset_security/group_roles_edit.mako index 825ea2b4543..69acf372fe3 100644 --- a/templates/admin/dataset_security/group_roles_edit.mako +++ b/templates/admin/dataset_security/group_roles_edit.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a row <%def name="render_row( role, ctr, anchored, curr_anchor, check )"> @@ -17,12 +18,12 @@ -%if msg: -
    ${msg}
    -%endif -

    Roles associated with group '${group.name}'

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( roles ) == 0: %else: diff --git a/templates/admin/dataset_security/groups.mako b/templates/admin/dataset_security/groups.mako index 3b92b8ccf99..391aa727b1d 100644 --- a/templates/admin/dataset_security/groups.mako +++ b/templates/admin/dataset_security/groups.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <% import galaxy.model @@ -48,10 +49,6 @@ -%if msg: -
    ${msg}
    -%endif -

    Groups

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( groups_members_roles ) == 0: There are no Galaxy groups %else: diff --git a/templates/admin/dataset_security/index.mako b/templates/admin/dataset_security/index.mako deleted file mode 100644 index 1a013ec1fc6..00000000000 --- a/templates/admin/dataset_security/index.mako +++ /dev/null @@ -1,13 +0,0 @@ -<%inherit file="/base.mako"/> - -<%def name="title()">Dataset Security -
    -
    Dataset Security
    -
    There are no Galaxy users
    There are no Galaxy roles
    - %if msg: - - %endif - - -

    ${msg}

    Groups
    Users
    -
    diff --git a/templates/admin/dataset_security/role.mako b/templates/admin/dataset_security/role.mako index 63add3c2bb3..63e9c450986 100644 --- a/templates/admin/dataset_security/role.mako +++ b/templates/admin/dataset_security/role.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <%def name="javascripts()"> ${parent.javascripts()} @@ -42,6 +43,10 @@ $().ready(function() { }); +%if msg: + ${render_msg( msg, messagetype )} +%endif +
    Role '${role.name}'
    diff --git a/templates/admin/dataset_security/role_create.mako b/templates/admin/dataset_security/role_create.mako index f9954c16488..e709c079176 100644 --- a/templates/admin/dataset_security/role_create.mako +++ b/templates/admin/dataset_security/role_create.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a user row <%def name="render_user_row( user, ctr )"> @@ -29,12 +30,11 @@ -%if msg: -
    ${msg}
    -%endif -

    Create Role

    - + +%if msg: + ${render_msg( msg, messagetype )} +%endif diff --git a/templates/admin/dataset_security/roles.mako b/templates/admin/dataset_security/roles.mako index fe0ff71d463..0e46ca82162 100644 --- a/templates/admin/dataset_security/roles.mako +++ b/templates/admin/dataset_security/roles.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <% import galaxy.model @@ -41,10 +42,6 @@ -%if msg: -
    ${msg}
    -%endif -

    Non-private Roles

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( roles ) == 0: There are no non-private Galaxy roles %else: diff --git a/templates/admin/dataset_security/user.mako b/templates/admin/dataset_security/user.mako index 49f0b2e07b7..aff1479944a 100644 --- a/templates/admin/dataset_security/user.mako +++ b/templates/admin/dataset_security/user.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <% import galaxy.model @@ -30,12 +31,12 @@ +

    User '${user.email}'

    + %if msg: -
    ${msg}
    + ${render_msg( msg, messagetype )} %endif -

    User '${user.email}'

    - %if len( groups ) == 0 and len( roles ) == 0: User '${user.email}' belongs to no groups and is associated with no roles %else: diff --git a/templates/admin/dataset_security/user_groups_edit.mako b/templates/admin/dataset_security/user_groups_edit.mako index 222657f2d8a..fa27a1655d7 100644 --- a/templates/admin/dataset_security/user_groups_edit.mako +++ b/templates/admin/dataset_security/user_groups_edit.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> ## Render a row <%def name="render_row( group, ctr, anchored, curr_anchor, check )"> @@ -17,12 +18,12 @@ -%if msg: -
    ${msg}
    -%endif -

    User '${user.email}' Associated Groups

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( groups ) == 0: %else: diff --git a/templates/admin/dataset_security/users.mako b/templates/admin/dataset_security/users.mako index cfff791eb12..e71f7c64f93 100644 --- a/templates/admin/dataset_security/users.mako +++ b/templates/admin/dataset_security/users.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <% import galaxy.model @@ -39,12 +40,12 @@ -%if msg: -
    ${msg}
    -%endif -

    Users

    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if len( users_groups_roles ) == 0: There are no Galaxy users %else: diff --git a/templates/admin/library/add_dataset_from_history.mako b/templates/admin/library/add_dataset_from_history.mako index 5a3428678d8..e8fd815bba5 100644 --- a/templates/admin/library/add_dataset_from_history.mako +++ b/templates/admin/library/add_dataset_from_history.mako @@ -1,21 +1,13 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <%def name="title()">Add Dataset to Library from History -%if error_msg: -

    -

    ${error_msg}
    -
    -

    +%if msg: + ${render_msg( msg, messagetype )} %endif -%if ok_msg: -

    -

    ${ok_msg}
    -
    -

    -%endif -

    +

    -
    Active Datasets in your current history (${history.name})
    +
    Active datasets in your current history (${history.name})
    @@ -24,7 +16,7 @@ ${dataset.hid}: ${dataset.name}
    %endfor - +
    diff --git a/templates/admin/library/browser.mako b/templates/admin/library/browser.mako index ad385e58e4d..ed9da94ade4 100644 --- a/templates/admin/library/browser.mako +++ b/templates/admin/library/browser.mako @@ -1,5 +1,6 @@ <%inherit file="/base.mako"/> <%namespace file="common.mako" import="render_dataset" /> +<%namespace file="/message.mako" import="render_msg" /> <%def name="title()">Import from Library <%def name="stylesheets()"> @@ -58,7 +59,7 @@ }); function checkForm() { if ( $("select#action_on_datasets_select option:selected").text() == "delete" ) { - if ( confirm( "Are you sure you want to delete these datasets?" ) ) { + if ( confirm( "Click OK to delete these datasets?" ) ) { return true; } else { return false; @@ -97,12 +98,12 @@ %if not deleted: %endif @@ -147,18 +148,6 @@ Libraries -%if msg: - <% - try: - messagetype - except: - messagetype = "done" - %> -

    -

    ${msg}
    -

    -%endif -

      %if not deleted:
    • @@ -170,6 +159,10 @@ %endif
    +%if msg: + ${render_msg( msg, messagetype )} +%endif + %if not libraries: %if deleted: There are no deleted libraries diff --git a/templates/admin/library/common.mako b/templates/admin/library/common.mako index 8ead836c7cc..a88271cd4b5 100644 --- a/templates/admin/library/common.mako +++ b/templates/admin/library/common.mako @@ -50,7 +50,7 @@ %endif @@ -85,24 +85,13 @@
    ${data.display_peek()}
    %endif ## Recurse for child datasets - %if len( data.children ) > 0: - ## FIXME: This should not be in the template, there should - ## be a 'visible_children' method on dataset. - <% - children = [] - for child in data.children: - if child.visible: - children.append( child ) - %> - %if len( children ) > 0: -
    - There are ${len( children )} secondary datasets. - %for idx, child in enumerate(children): - ##${render_dataset( child, idx + 1 )} - ${ render_dataset( child, selected, deleted ) } - %endfor -
    - %endif + %if len( data.visible_children ) > 0: +
    + There are ${len( data.visible_children )} secondary datasets. + %for idx, child in enumerate( data.visible_children ): + ${ render_dataset( child, selected, deleted ) } + %endfor +
    %endif diff --git a/templates/admin/library/new_dataset.mako b/templates/admin/library/new_dataset.mako index de862d3f7f1..074d6e6f7ca 100644 --- a/templates/admin/library/new_dataset.mako +++ b/templates/admin/library/new_dataset.mako @@ -1,9 +1,10 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <% import os %> %if msg: -

    ${msg}

    + ${render_msg( msg, messagetype )} %endif
    diff --git a/templates/admin/library/new_folder.mako b/templates/admin/library/new_folder.mako index 47be9f9e5a2..b8fca3b1ba6 100644 --- a/templates/admin/library/new_folder.mako +++ b/templates/admin/library/new_folder.mako @@ -1,7 +1,8 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> %if msg: -

    ${msg}

    + ${render_msg( msg, messagetype )} %endif
    diff --git a/templates/admin/library/new_library.mako b/templates/admin/library/new_library.mako index b9609c1d6d5..8b33fad4c70 100644 --- a/templates/admin/library/new_library.mako +++ b/templates/admin/library/new_library.mako @@ -1,7 +1,8 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> %if msg: -

    ${msg}

    + ${render_msg( msg, messagetype )} %endif
    diff --git a/templates/admin/library/rename_folder.mako b/templates/admin/library/rename_folder.mako index 8a827f0d2b4..349fed2ecbe 100644 --- a/templates/admin/library/rename_folder.mako +++ b/templates/admin/library/rename_folder.mako @@ -1,7 +1,8 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> %if msg: -

    ${msg}

    + ${render_msg( msg, messagetype )} %endif
    diff --git a/templates/admin/library/rename_library.mako b/templates/admin/library/rename_library.mako index acbbaeb2800..95f505e9046 100644 --- a/templates/admin/library/rename_library.mako +++ b/templates/admin/library/rename_library.mako @@ -1,7 +1,8 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> %if msg: -

    ${msg}

    + ${render_msg( msg, messagetype )} %endif
    @@ -25,19 +26,19 @@
    - +
    - +
    - +
    diff --git a/templates/admin/memdump.mako b/templates/admin/memdump.mako index e99c5585c19..edbf154e5a5 100644 --- a/templates/admin/memdump.mako +++ b/templates/admin/memdump.mako @@ -1,4 +1,5 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> <%def name="title()">Memory Profiling <% @@ -44,7 +45,7 @@ %if msg: -
    ${msg}
    + ${render_msg( msg, messagetype )} %endif %if heap is None: diff --git a/templates/admin/reload_tool.mako b/templates/admin/reload_tool.mako index 3b8e568cfd4..f108033a140 100644 --- a/templates/admin/reload_tool.mako +++ b/templates/admin/reload_tool.mako @@ -1,7 +1,8 @@ <%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> %if msg: -
    ${msg}
    + ${render_msg( msg, messagetype )} %endif
    diff --git a/templates/base.mako b/templates/base.mako index e4f0d881a35..64437d13af9 100644 --- a/templates/base.mako +++ b/templates/base.mako @@ -1,16 +1,16 @@ - -${self.title()} - -${self.stylesheets()} -${self.javascripts()} - + + ${self.title()} + + ${self.stylesheets()} + ${self.javascripts()} + - - ${next.body()} - + + ${next.body()} + ## Default title @@ -28,4 +28,4 @@ ${self.javascripts()} ## - \ No newline at end of file + diff --git a/templates/base_panels.mako b/templates/base_panels.mako index 0d275ed44c2..c04ffb3d0f4 100644 --- a/templates/base_panels.mako +++ b/templates/base_panels.mako @@ -10,7 +10,7 @@ %> <%def name="init()"> -## Override + ## Override ## Default title @@ -40,10 +40,10 @@ ## Default javascripts <%def name="javascripts()"> - + ## Default late-load javascripts @@ -64,7 +64,7 @@ %endif - + ## Masthead <%def name="masthead()"> @@ -80,40 +80,42 @@ ${self.init()} - ${self.title()} - ${self.javascripts()} - ${self.stylesheets()} + ${self.title()} + ${self.javascripts()} + ${self.stylesheets()} - ## Background displays first -
    - ## Layer iframes over backgrounds -
    - ${self.masthead()} -
    + ## Background displays first +
    + ## Layer iframes over backgrounds +
    + ${self.masthead()} +
    %if self.message_box_visible: ${self.message_box_content()} %endif
    %if self.has_left_panel: -
    - ${self.left_panel()} -
    -
    +
    + ${self.left_panel()} +
    +
    + +
    %endif -
    - ${self.center_panel()} -
    +
    + ${self.center_panel()} +
    %if self.has_right_panel: -
    - +
    + %endif ## Allow other body level elements - ${next.body()} + ${next.body()} ## Scripts can be loaded later since they progressively add features to ## the panels, but do not change layout diff --git a/templates/library/browser.mako b/templates/library/browser.mako index ef0f94a5cfe..e9a15c4b690 100644 --- a/templates/library/browser.mako +++ b/templates/library/browser.mako @@ -1,5 +1,6 @@ <%inherit file="/base.mako"/> <%namespace file="common.mako" import="render_dataset" /> +<%namespace file="/message.mako" import="render_msg" /> <%def name="title()">Import from Library <%def name="stylesheets()"> @@ -78,67 +79,88 @@ <%def name="render_folder( parent, parent_pad )"> - <% - if not trans.app.security_agent.check_folder_contents( trans.user, parent ): - return "" - pad = parent_pad + 20 - if parent_pad == 0: - expander = "/static/images/silk/resultset_bottom.png" - folder = "/static/images/silk/folder_page.png" - subfolder = False - else: - expander = "/static/images/silk/resultset_next.png" - folder = "/static/images/silk/folder.png" - subfolder = True - %> -
  • -
    - - ${parent.name} - %if parent.description: - - ${parent.description} - %endif -
    -
  • - %if subfolder: -
      - %else: -
        - %endif - %for folder in parent.active_folders: - ${render_folder( folder, pad )} - %endfor - %for dataset in parent.active_datasets: - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=dataset.dataset ): -
      • ${render_dataset( dataset )}
      • - %endif - %endfor + <% + if not trans.app.security_agent.check_folder_contents( trans.user, parent ): + return "" + pad = parent_pad + 20 + if parent_pad == 0: + expander = "/static/images/silk/resultset_bottom.png" + folder = "/static/images/silk/folder_page.png" + subfolder = False + else: + expander = "/static/images/silk/resultset_next.png" + folder = "/static/images/silk/folder.png" + subfolder = True + %> +
      • +
        + + ${parent.name} + %if parent.description: + - ${parent.description} + %endif +
        +
      • + %if subfolder: +
          + %else: +
            + %endif + %for folder in parent.active_folders: + ${render_folder( folder, pad )} + %endfor + %for dataset in parent.active_datasets: + %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=dataset.dataset ): +
          • ${render_dataset( dataset )}
          • + %endif + %endfor

          Libraries

          -
          -
            -%for library in libraries: - %if trans.app.security_agent.check_folder_contents( trans.user, library ): -
    User ${user.email} is not a member of any groups
    - - - - -
    - - ${library.name} - %if library.description: - - ${library.description} + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +%if not libraries: + No libraries contain datasets that you are allowed to access +%else: + <% can_access = False %> + +
      + %for library in libraries: + %if trans.app.security_agent.check_folder_contents( trans.user, library ): + <% can_access = True %> +
    • +
      + + + + + + + +
      + + ${library.name} + %if library.description: + - ${library.description} + %endif + FormatDbInfo
      +
      +
    • +
        + ${render_folder( library.root_folder, 0 )} +
      +
      + %endif + %endfor +
    + %if can_access: + + %else: + No libraries contain datasets that you are allowed to access %endif -
    FormatDbInfo
    -
      - ${render_folder( library.root_folder, 0 )} -
    -
    - %endif -%endfor - - - + +%endif diff --git a/templates/library/common.mako b/templates/library/common.mako index 9861833113e..d1bf6a5b6d2 100644 --- a/templates/library/common.mako +++ b/templates/library/common.mako @@ -17,91 +17,75 @@
    %endif - ## Header row for history items (name, state, action buttons) - + ## Header row for history items (name, state, action buttons)
    - - %if data_state == 'running': -
    - %elif data_state != 'ok': -
    - %endif + + %if data_state == 'running': +
    + %elif data_state != 'ok': +
    + %endif
    - <%doc> -
    - display data - edit attributes - delete -
    - - - - - - -
    -
    - - view or edit attributes - -
    - - ${data.display_name()} -
    ${data.ext}${data.dbkey}${data.info}
    -
    - - ## Body for history items, extra info and actions, data "peek" - -
    - %if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): -
    You do not have permission to view this dataset.
    - %else: -
    - ${data.blurb} -
    -
    - %if data.has_data: - save - %for display_app in data.datatype.get_display_types(): - <% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %> - %if len( display_links ) > 0: - | ${data.datatype.get_display_label(display_app)} - %for display_name, display_link in display_links: - ${display_name} - %endfor - %endif - %endfor - %endif -
    - %if data.peek != "no peek": -
    ${data.display_peek()}
    - %endif - %endif - ## Recurse for child datasets - %if len( data.children ) > 0: - ## FIXME: This should not be in the template, there should - ## be a 'visible_children' method on dataset. - <% - children = [] - for child in data.children: - if child.visible: - children.append( child ) - %> - %if len( children ) > 0: -
    - There are ${len( children )} secondary datasets. - %for idx, child in enumerate(children): - ${render_dataset( child, idx + 1 )} - %endfor + <%doc> +
    + display data + edit attributes + delete +
    + + + + + + + + +
    + + + ${data.display_name()} + ${data.ext}${data.dbkey}${data.info}
    +
    + + ## Body for history items, extra info and actions, data "peek" +
    + %if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): +
    You do not have permission to view this dataset.
    + %else: +
    ${data.blurb}
    +
    + %if data.has_data: + save + %for display_app in data.datatype.get_display_types(): + <% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %> + %if len( display_links ) > 0: + | ${data.datatype.get_display_label(display_app)} + %for display_name, display_link in display_links: + ${display_name} + %endfor + %endif + %endfor %endif +
    + %if data.peek != "no peek": +
    ${data.display_peek()}
    %endif -
    + %endif + ## Recurse for child datasets + %if len( data.visible_children ) > 0: +
    + There are ${len( data.visible_children )} secondary datasets. + %for idx, child in enumerate( data.visible_children ): + ${render_dataset( child )} + %endfor +
    + %endif
    diff --git a/templates/message.mako b/templates/message.mako index 551b60c4735..19d11fd98f9 100644 --- a/templates/message.mako +++ b/templates/message.mako @@ -1,32 +1,37 @@ <%inherit file="/base.mako"/> <%def name="javascripts()"> -${parent.javascripts()} - + if ( parent.handle_minwidth_hint ) + { + parent.handle_minwidth_hint( -1 ); + } +
    ${message}
    + +## Render a message +<%def name="render_msg( msg, messagetype='done' )"> +
    ${msg}
    + \ No newline at end of file diff --git a/test/base/twilltestcase.py b/test/base/twilltestcase.py index f0f820023ab..ab51a378605 100644 --- a/test/base/twilltestcase.py +++ b/test/base/twilltestcase.py @@ -674,7 +674,7 @@ class TwillTestCase( unittest.TestCase ): self.home() raise AssertionError( 'Exception caught attempting to create library: %s' % str( err ) ) self.home() - def rename_library( self, library_id, name='New Test Library Renamed', description='New Test Library Description Re-described' ): + def rename_library( self, library_id, name='New Test Library Renamed', description='New Test Library Description Re-described', root_folder='' ): """Rename a library""" try: self.visit_url( "%s/admin/library?rename=True&id=%s" % ( self.url, library_id ) ) @@ -682,6 +682,8 @@ class TwillTestCase( unittest.TestCase ): self.check_page_for_string( 'Edit library name and description' ) tc.fv( "1", "name", name ) # form field 1 is the field named name... tc.fv( "1", "description", description ) # form field 2 is the field named description... + if root_folder: + tc.fv( "1", "root_folder", root_folder ) tc.submit( "rename_library_button" ) except AssertionError, err: self.home() @@ -733,6 +735,25 @@ class TwillTestCase( unittest.TestCase ): self.home() raise AssertionError( 'Exception caught attempting to create add a dataset to a folder: %s' % str( err ) ) self.home() + def add_dataset_to_folder_from_history( self, folder_id ): + """Copy a dataset from the current history to a library folder""" + try: + # Create a new history + self.new_history() + self.upload_file( "1.bed" ) + self.verify_dataset_correctness( "1.bed" ) + self.visit_url( "%s/admin/add_dataset_to_folder_from_history?folder_id=%s" % ( self.url, folder_id ) ) + self.last_page() + self.check_page_for_string( 'Active datasets in your current history' ) + tc.fv( "1", "folder_id", folder_id ) + tc.fv( "1", "ids", "1" ) + tc.submit( "add_dataset_from_history_button" ) + self.last_page() + self.check_page_for_string( 'Added the following datasets to the library folder: 1.bed' ) + except AssertionError, err: + self.home() + raise AssertionError( 'Exception caught attempting to create add a dataset to a folder: %s' % str( err ) ) + self.home() def add_datasets_from_library_dir( self, folder_id, extension='auto', dbkey='hg18', roles=[] ): """Add a directory of datasets to a folder""" try: diff --git a/test/functional/test_security_and_libraries.py b/test/functional/test_security_and_libraries.py index 4554d6ff93f..0c9e0ace5f6 100644 --- a/test/functional/test_security_and_libraries.py +++ b/test/functional/test_security_and_libraries.py @@ -129,11 +129,11 @@ class TestHistory( TwillTestCase ): galaxy.model.Library.table.c.deleted==False ) ).first() def test_21_rename_library( self ): """Testing renaming a library""" - self.rename_library( str( library.id ), name='New Test Library Renamed', description='New Test Library Description Re-described' ) + self.rename_library( str( library.id ), name='New Test Library Renamed', description='New Test Library Description Re-described', root_folder='on' ) self.visit_page( 'admin/libraries' ) self.check_page_for_string( "New Test Library Renamed" ) # Rename it back to what it was originally - self.rename_library( str( library.id ), name='New Test Library', description='New Test Library Description' ) + self.rename_library( str( library.id ), name='New Test Library', description='New Test Library Description', root_folder='on' ) def test_24_rename_root_folder( self ): """Testing renaming a library root folder""" folder = library.root_folder @@ -148,7 +148,11 @@ class TestHistory( TwillTestCase ): self.check_page_for_string( "1.bed" ) self.check_page_for_string( "bed" ) self.check_page_for_string( "hg18" ) - def test_30_add_new_folder( self ): + def test_30_copy_dataset_from_history_to_root_folder( self ): + """Testing copying a dataset from the current history to a library root folder""" + folder = library.root_folder + self.add_dataset_to_folder_from_history( str( folder.id ) ) + def test_33_add_new_folder( self ): """Testing adding a folder to a library root folder""" root_folder = library.root_folder name = 'New Test Folder' @@ -160,26 +164,26 @@ class TestHistory( TwillTestCase ): galaxy.model.LibraryFolder.table.c.description==description ) ).first() self.visit_page( 'admin/libraries' ) self.check_page_for_string( "New Test Folder" ) - def test_33_add_datasets_from_library_dir( self ): - """Testing adding dataset from library directory to sub-folder""" + def test_36_add_datasets_from_library_dir( self ): + """Testing adding several datasets from library directory to sub-folder""" self.add_datasets_from_library_dir( str( new_test_folder.id ), roles=[ str( new_test_role.id ) ] ) - def test_36_mark_group_deleted( self ): + def test_39_mark_group_deleted( self ): """Testing marking a group as deleted""" self.visit_page( "admin/groups" ) self.check_page_for_string( another_test_group.name ) self.mark_group_deleted( str( another_test_group.id ) ) - def test_39_undelete_group( self ): + def test_42_undelete_group( self ): """Testing undeleting a deleted group""" self.undelete_group( str( another_test_group.id ) ) - def test_42_mark_role_deleted( self ): + def test_45_mark_role_deleted( self ): """Testing marking a role as deleted""" self.visit_page( "admin/roles" ) self.check_page_for_string( another_test_role.name ) self.mark_role_deleted( str( another_test_role.id ) ) - def test_45_undelete_role( self ): + def test_48_undelete_role( self ): """Testing undeleting a deleted role""" self.undelete_role( str( another_test_role.id ) ) - def test_48_mark_library_deleted( self ): + def test_51_mark_library_deleted( self ): """Testing marking a library as deleted""" self.mark_library_deleted( str( library.id ) ) # Make sure the library was deleted @@ -203,7 +207,7 @@ class TestHistory( TwillTestCase ): if lfda.dataset.deleted: raise AssertionError( 'The dataset with id "%s" has been marked as deleted when it should not have been.' % lfda.dataset.id ) check_folder( library.root_folder ) - def test_51_mark_library_undeleted( self ): + def test_54_mark_library_undeleted( self ): """Testing marking a library as not deleted""" self.mark_library_undeleted( str( library.id ) ) # Make sure the library is undeleted @@ -232,7 +236,7 @@ class TestHistory( TwillTestCase ): library.refresh() if not library.deleted: raise AssertionError( 'The library id %s named "%s" has not been marked as deleted after it was undeleted.' % ( str( library.id ), library.name ) ) - def test_54_purge_group( self ): + def test_57_purge_group( self ): """Testing purging a group""" group_id = str( another_test_group.id ) self.purge_group( group_id ) @@ -244,7 +248,7 @@ class TestHistory( TwillTestCase ): gra = galaxy.model.GroupRoleAssociation.filter( galaxy.model.GroupRoleAssociation.table.c.group_id == group_id ).all() if gra: raise AssertionError( "Purging the group did not delete the GroupRoleAssociations for group_id '%s'" % group_id ) - def test_57_purge_role( self ): + def test_60_purge_role( self ): """Testing purging a role""" role_id = str( another_test_role.id ) self.purge_role( role_id ) @@ -256,7 +260,7 @@ class TestHistory( TwillTestCase ): adra = galaxy.model.ActionDatasetRoleAssociation.filter( galaxy.model.ActionDatasetRoleAssociation.table.c.role_id == role_id ).all() if adra: raise AssertionError( "Purging the role did not delete the ActionDatasetRoleAssociations for role_id '%s'" % role_id ) - def test_60_purge_library( self ): + def test_63_purge_library( self ): """Testing purging a library""" self.purge_library( str( library.id ) ) # Make sure the library was purged From 1369b8d199a59509a725d3f10268825b060c4f00 Mon Sep 17 00:00:00 2001 From: Nate Coraor Date: Thu, 20 Nov 2008 15:14:47 -0500 Subject: [PATCH 3/3] You can now require that users log in to use Galaxy. The sample config is way different but it's only because I cleaned it up a bit. The only new options are require_login/allow_user_creation. --- lib/galaxy/config.py | 4 +- lib/galaxy/util/__init__.py | 12 ++ lib/galaxy/web/__init__.py | 2 +- lib/galaxy/web/controllers/admin.py | 161 ++++++------------ lib/galaxy/web/controllers/root.py | 7 +- lib/galaxy/web/controllers/user.py | 75 ++++++-- lib/galaxy/web/framework/__init__.py | 39 ++++- lib/galaxy/web/framework/base.py | 22 ++- static/scripts/galaxy.panels.js | 16 +- static/scripts/packed/galaxy.panels.js | 2 +- .../scripts/packed/galaxy.ui.scrollPanel.js | 2 +- templates/admin/dataset_security/users.mako | 4 + templates/admin/index.mako | 3 +- templates/base_panels.mako | 2 + templates/form.mako | 4 + templates/message.mako | 8 +- templates/no_access.mako | 15 ++ templates/root/index.mako | 19 ++- templates/root/masthead.mako | 55 +++--- universe_wsgi.ini.sample | 156 +++++++++-------- 20 files changed, 357 insertions(+), 251 deletions(-) create mode 100644 templates/no_access.mako diff --git a/lib/galaxy/config.py b/lib/galaxy/config.py index 560062ed8cd..a8df982d53c 100644 --- a/lib/galaxy/config.py +++ b/lib/galaxy/config.py @@ -38,10 +38,12 @@ class Configuration( object ): self.id_secret = kwargs.get( "id_secret", "USING THE DEFAULT IS NOT SECURE!" ) self.use_remote_user = string_as_bool( kwargs.get( "use_remote_user", "False" ) ) self.remote_user_maildomain = kwargs.get( "remote_user_maildomain", None ) + self.require_login = string_as_bool( kwargs.get( "require_login", "False" ) ) + self.allow_user_creation = string_as_bool( kwargs.get( "allow_user_creation", "True" ) ) self.template_path = resolve_path( kwargs.get( "template_path", "templates" ), self.root ) self.template_cache = resolve_path( kwargs.get( "template_cache_path", "database/compiled_templates" ), self.root ) self.local_job_queue_workers = int( kwargs.get( "local_job_queue_workers", "5" ) ) - self.cluster_job_queue_workers = int( kwargs.get( "cluster_job_queue_workers", "5" ) ) + self.cluster_job_queue_workers = int( kwargs.get( "cluster_job_queue_workers", "3" ) ) self.job_scheduler_policy = kwargs.get("job_scheduler_policy", "FIFO") self.job_queue_cleanup_interval = int( kwargs.get("job_queue_cleanup_interval", "5") ) self.job_working_directory = resolve_path( kwargs.get( "job_working_directory", "database/job_working_directory" ), self.root ) diff --git a/lib/galaxy/util/__init__.py b/lib/galaxy/util/__init__.py index 5c7d068f861..f82997f532c 100644 --- a/lib/galaxy/util/__init__.py +++ b/lib/galaxy/util/__init__.py @@ -246,6 +246,18 @@ def string_as_bool( string ): else: return False +def listify( item ): + """ + Make a single item a single item list, or return a list if passed a + list. Passing a None returns an empty list. + """ + if item is None: + return [] + elif isinstance( item, list ): + return item + else: + return [ item ] + def commaify(amount): orig = amount new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', amount) diff --git a/lib/galaxy/web/__init__.py b/lib/galaxy/web/__init__.py index 508e2b35037..15bb7888368 100644 --- a/lib/galaxy/web/__init__.py +++ b/lib/galaxy/web/__init__.py @@ -2,5 +2,5 @@ The Galaxy web application. """ -from framework import expose, json, require_login, url_for, error, form, FormBuilder +from framework import expose, json, require_login, require_admin, url_for, error, form, FormBuilder diff --git a/lib/galaxy/web/controllers/admin.py b/lib/galaxy/web/controllers/admin.py index f3ae60abc5a..7ca8d20233f 100644 --- a/lib/galaxy/web/controllers/admin.py +++ b/lib/galaxy/web/controllers/admin.py @@ -13,44 +13,28 @@ import sqlalchemy as sa import logging log = logging.getLogger( __name__ ) -no_privilege_msg = "You must have Galaxy administrator privileges to use this feature." - class Admin( BaseController ): - def user_is_admin( self, trans ): - admin_users = trans.app.config.get( "admin_users", "" ).split( "," ) - if not admin_users: - return False - user = trans.get_user() - if not user: - return False - if not user.email in admin_users: - return False - return True @web.expose + @web.require_admin def index( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) return trans.fill_template( '/admin/index.mako', msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def center( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) return trans.fill_template( '/admin/center.mako' ) @web.expose + @web.require_admin def reload_tool( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) return trans.fill_template( '/admin/reload_tool.mako', toolbox=self.app.toolbox, msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def tool_reload( self, trans, tool_version=None, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) tool_id = params.tool_id self.app.toolbox.reload( tool_id ) @@ -59,9 +43,8 @@ class Admin( BaseController ): # Galaxy Role Stuff @web.expose + @web.require_admin def roles( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -72,9 +55,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def create_role( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -89,9 +71,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def new_role( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) name = params.name description = params.description @@ -108,14 +89,14 @@ class Admin( BaseController ): type=trans.app.model.Role.types.ADMIN ) role.flush() # Add the users - users = listify( params.users ) + users = util.listify( params.users ) for user_id in users: user = galaxy.model.User.get( user_id ) # Create the UserRoleAssociation ura = galaxy.model.UserRoleAssociation( user, role ) ura.flush() # Add the groups - groups = listify( params.groups ) + groups = util.listify( params.groups ) for group_id in groups: group = galaxy.model.Group.get( group_id ) # Create the GroupRoleAssociation @@ -124,9 +105,8 @@ class Admin( BaseController ): msg = "The new role has been created with %s associated users and %s associated groups" % ( str( len( users ) ), str( len( groups ) ) ) trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def role( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -180,12 +160,11 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def role_members_edit( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) role = galaxy.model.Role.get( int( params.role_id ) ) - in_users = [ trans.app.model.User.get( x ) for x in listify( params.in_users ) ] + in_users = [ trans.app.model.User.get( x ) for x in util.listify( params.in_users ) ] for ura in role.users: user = trans.app.model.User.get( ura.user_id ) if user not in in_users: @@ -200,15 +179,14 @@ class Admin( BaseController ): if role == dhp.role: dhp.delete() dhp.flush() - in_groups = [ trans.app.model.Group.get( x ) for x in listify( params.in_groups ) ] + in_groups = [ trans.app.model.Group.get( x ) for x in util.listify( params.in_groups ) ] trans.app.security_agent.set_entity_role_associations( roles=[ role ], users=in_users, groups=in_groups ) role.refresh() msg = "The role has been updated with %s associated users and %s associated groups" % ( str( len( in_users ) ), str( len( in_groups ) ) ) trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def mark_role_deleted( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) role = galaxy.model.Role.get( int( params.role_id ) ) role.deleted = True @@ -216,9 +194,8 @@ class Admin( BaseController ): msg = "The role has been marked as deleted." trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def deleted_roles( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -242,9 +219,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def undelete_role( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) role = galaxy.model.Role.get( int( params.role_id ) ) role.deleted = False @@ -252,9 +228,8 @@ class Admin( BaseController ): msg = "The role has been marked as not deleted." trans.response.send_redirect( web.url_for( action='roles', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def purge_role( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) role = galaxy.model.Role.get( int( params.role_id ) ) # Delete UserRoleAssociations @@ -285,9 +260,8 @@ class Admin( BaseController ): # Galaxy Group Stuff @web.expose + @web.require_admin def groups( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -311,9 +285,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def create_group( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -329,9 +302,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def new_group( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) name = params.name if not name: @@ -345,7 +317,7 @@ class Admin( BaseController ): group = galaxy.model.Group( name ) group.flush() # Add the members - members = listify( params.members ) + members = util.listify( params.members ) for user_id in members: user = galaxy.model.User.get( user_id ) # Create the UserGroupAssociation @@ -365,9 +337,8 @@ class Admin( BaseController ): msg = "The new group has been created with %s members and %s associated roles" % ( str( len( members ) ), str( len( roles ) ) ) trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def group_members_edit( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -382,12 +353,11 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def update_group_members( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) group_id = int( params.group_id ) - members = listify( params.members ) + members = util.listify( params.members ) group = galaxy.model.Group.get( group_id ) # This is tricky since we have default association tables with # records referring to members of this group. Because of this, @@ -411,9 +381,8 @@ class Admin( BaseController ): # TODO: We probably don't want the following 2 methods since managing roles should be # restricted to the Role page due to private roles and rules governing them @web.expose + @web.require_admin def group_roles_edit( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -428,12 +397,11 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def update_group_roles( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) group_id = int( params.group_id ) - roles = listify( params.roles ) + roles = util.listify( params.roles ) group = galaxy.model.Group.get( group_id ) # This is tricky since we have default association tables with # records referring to members of this group. Because of this, @@ -455,9 +423,8 @@ class Admin( BaseController ): msg = "Group updated with a total of %s associated roles" % len( roles ) trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def mark_group_deleted( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) group = galaxy.model.Group.get( int( params.group_id ) ) group.deleted = True @@ -465,9 +432,8 @@ class Admin( BaseController ): msg = "The group has been marked as deleted." trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def deleted_groups( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -491,9 +457,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def undelete_group( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) group = galaxy.model.Group.get( int( params.group_id ) ) group.deleted = False @@ -501,9 +466,8 @@ class Admin( BaseController ): msg = "The group has been marked as not deleted." trans.response.send_redirect( web.url_for( action='groups', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def purge_group( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) group = galaxy.model.Group.get( int( params.group_id ) ) # Delete UserGroupAssociations @@ -522,9 +486,8 @@ class Admin( BaseController ): # Galaxy User Stuff @web.expose + @web.require_admin def users( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -545,9 +508,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def user( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) user_id = params.user_id msg = params.msg @@ -568,9 +530,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def user_groups_edit( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -589,12 +550,11 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def update_user_groups( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) user_id = int( params.user_id ) - groups = listify( params.groups ) + groups = util.listify( params.groups ) user = galaxy.model.User.get( user_id ) # First remove existing UserGroupAssociations that are not in the received groups param for uga in user.groups: @@ -613,9 +573,8 @@ class Admin( BaseController ): # Galaxy Library Stuff @web.expose + @web.require_admin def library_browser( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -629,9 +588,8 @@ class Admin( BaseController ): messagetype=messagetype ) libraries = library_browser @web.expose + @web.require_admin def library( self, trans, id=None, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -697,9 +655,8 @@ class Admin( BaseController ): msg = 'The library and all of its contents have been marked deleted' return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def deleted_libraries( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -712,9 +669,8 @@ class Admin( BaseController ): msg=msg, messagetype=messagetype ) @web.expose + @web.require_admin def undelete_library( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) library = galaxy.model.Library.get( int( params.id ) ) def undelete_folder( library_folder ): @@ -731,9 +687,8 @@ class Admin( BaseController ): msg = "The library and all of its contents have been marked not deleted" return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def purge_library( self, trans, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) library = galaxy.model.Library.get( int( params.id ) ) def purge_folder( library_folder ): @@ -759,9 +714,8 @@ class Admin( BaseController ): msg = "The library and all of its contents have been purged, datasets will be removed from disk via the cleanup_datasets script" return trans.response.send_redirect( web.url_for( action='deleted_libraries', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def folder( self, trans, id, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -819,9 +773,8 @@ class Admin( BaseController ): msg = 'The folder %s and all of its contents have been marked deleted' % folder.name return trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='done' ) ) @web.expose + @web.require_admin def dataset( self, trans, id=None, name="Unnamed", info='no info', extension=None, folder_id=None, dbkey=None, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) if isinstance( dbkey, list ): last_used_build = dbkey[0] else: @@ -919,7 +872,7 @@ class Admin( BaseController ): space_to_tab = True roles = [] role_ids = params.get( 'roles', [] ) - for role_id in listify( role_ids ): + for role_id in util.listify( role_ids ): roles.append( galaxy.model.Role.get( role_id ) ) temp_name = "" data_list = [] @@ -1035,7 +988,7 @@ class Admin( BaseController ): # The user clicked the Save button on the 'Associate With Roles' form permissions = {} for k, v in trans.app.model.Dataset.permitted_actions.items(): - in_roles = [ trans.app.model.Role.get( x ) for x in listify( p.get( k + '_in', [] ) ) ] + in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( p.get( k + '_in', [] ) ) ] permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles trans.app.security_agent.set_dataset_permissions( lda.dataset, permissions ) lda.dataset.refresh() @@ -1115,7 +1068,7 @@ class Admin( BaseController ): #p = util.Params( kwd ) permissions = {} for k, v in trans.app.model.Dataset.permitted_actions.items(): - in_roles = [ trans.app.model.Role.get( x ) for x in listify( params.get( k + '_in', [] ) ) ] + in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ] permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles for lfda in lfdas: trans.app.security_agent.set_dataset_permissions( lfda.dataset, permissions ) @@ -1191,10 +1144,9 @@ class Admin( BaseController ): # return( True, False ) return ( True, True ) @web.expose + @web.require_admin def datasets( self, trans, **kwd ): # This method is used by the select list labeled "Perform action on selected datasets" on the admin library browser. - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) params = util.Params( kwd ) msg = params.msg messagetype = params.get( 'messagetype', 'done' ) @@ -1202,7 +1154,7 @@ class Admin( BaseController ): if not params.dataset_ids: msg = "At least one dataset must be selected for %s" % params.action trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype='error' ) ) - dataset_ids = listify( params.dataset_ids ) + dataset_ids = util.listify( params.dataset_ids ) if params.action == 'edit': trans.response.send_redirect( web.url_for( action='dataset', id=",".join( dataset_ids ), msg=msg, messagetype=messagetype ) ) elif params.action == 'delete': @@ -1218,9 +1170,8 @@ class Admin( BaseController ): else: trans.response.send_redirect( web.url_for( action='library_browser', msg=msg, messagetype=messagetype ) ) @web.expose + @web.require_admin def delete_dataset( self, trans, id=None, **kwd): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) if id: # id is a LibraryFolderDatasetAssociation.id lfda = trans.app.model.LibraryFolderDatasetAssociation.get( id ) @@ -1238,9 +1189,8 @@ class Admin( BaseController ): messagetype='error' ) ) @web.expose + @web.require_admin def memdump( self, trans, ids = 'None', sorts = 'None', pages = 'None', new_id = None, new_sort = None, **kwd ): - if not self.user_is_admin( trans ): - return trans.show_error_message( no_privilege_msg ) if self.app.memdump is None: return trans.show_error_message( "Memdump is not enabled (set use_memdump = True in universe_wsgi.ini)" ) heap = self.app.memdump.get() @@ -1278,14 +1228,3 @@ class Admin( BaseController ): breadcrumb += ".theone" heap = heap.theone return trans.fill_template( '/admin/memdump.mako', heap = heap, ids = ids, sorts = sorts, breadcrumb = breadcrumb, msg = msg ) - -def listify( item, return_none=False ): - """ - Since single params are not a single item list - """ - if item is None: - return [] - elif isinstance( item, list ): - return item - else: - return [ item ] diff --git a/lib/galaxy/web/controllers/root.py b/lib/galaxy/web/controllers/root.py index eb6ca6f4b90..5d7949ed347 100644 --- a/lib/galaxy/web/controllers/root.py +++ b/lib/galaxy/web/controllers/root.py @@ -25,7 +25,10 @@ class RootController( BaseController ): @web.expose def tool_menu( self, trans ): - return trans.fill_template('/root/tool_menu.mako', toolbox=self.get_toolbox() ) + if trans.app.config.require_login and not trans.user: + return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy tools.' ) + else: + return trans.fill_template('/root/tool_menu.mako', toolbox=self.get_toolbox() ) @web.expose def tool_help( self, trans, id ): @@ -51,6 +54,8 @@ class RootController( BaseController ): NOTE: No longer accepts "id" or "template" options for security reasons. """ history = trans.get_history() + if trans.app.config.require_login and not trans.user: + return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' ) if as_xml: trans.response.set_content_type('text/xml') return trans.fill_template_mako( "root/history_as_xml.mako", history=history ) diff --git a/lib/galaxy/web/controllers/user.py b/lib/galaxy/web/controllers/user.py index 075474869b1..695bda82dd1 100644 --- a/lib/galaxy/web/controllers/user.py +++ b/lib/galaxy/web/controllers/user.py @@ -9,6 +9,17 @@ from random import choice log = logging.getLogger( __name__ ) +require_login_template = """ +

    Welcome to Galaxy

    + +

    + This installation of Galaxy has been configured such that only users who are logged in may use it.%s +

    +

    +""" +require_login_nocreation_template = require_login_template % "" +require_login_creation_template = require_login_template % " If you don't already have an account, you may create one." + class User( BaseController ): @web.expose @@ -75,6 +86,10 @@ class User( BaseController ): m0 = trans.app.memory_usage.memory() email_error = password_error = None # Attempt login + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] if email or password: user = trans.app.model.User.filter_by( email=email ).first() if not user: @@ -87,33 +102,50 @@ class User( BaseController ): else: trans.handle_user_login( user ) trans.log_event( "User logged in" ) - return trans.show_ok_message( "Now logged in as " + user.email, refresh_frames=['masthead', 'history'] ) + return trans.show_ok_message( "Now logged in as " + user.email, refresh_frames=refresh_frames ) if trans.app.memory_usage: m1 = trans.app.memory_usage.memory( m0, pretty=True ) log.info( "End of user/login, memory used increased by %s" % m1 ) - return trans.show_form( - web.FormBuilder( web.url_for(), "Login", submit_text="Login" ) - .add_text( "email", "Email address", value=email, error=email_error ) + form = web.FormBuilder( web.url_for(), "Login", submit_text="Login" ) \ + .add_text( "email", "Email address", value=email, error=email_error ) \ .add_password( "password", "Password", value='', error=password_error, - help="Forgot password? Reset here" % web.url_for( action='reset_password' ) ) ) + help="Forgot password? Reset here" % web.url_for( action='reset_password' ) ) + if trans.app.config.require_login: + if trans.app.config.allow_user_creation: + return trans.show_form( form, header = require_login_creation_template % web.url_for( action = 'create' ) ) + else: + return trans.show_form( form, header = require_login_nocreation_template ) + else: + return trans.show_form( form ) + @web.expose def logout( self, trans ): if trans.app.memory_usage: # Keep track of memory usage m0 = trans.app.memory_usage.memory() + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] # Since logging an event requires a session, we'll log prior to ending the session trans.log_event( "User logged out" ) trans.handle_user_logout() if trans.app.memory_usage: m1 = trans.app.memory_usage.memory( m0, pretty=True ) log.info( "End of user/logout, memory used increased by %s" % m1 ) - return trans.show_ok_message( "You are no longer logged in", refresh_frames=['masthead', 'history'] ) + return trans.show_ok_message( "You are no longer logged in.", refresh_frames=refresh_frames ) @web.expose - def create( self, trans, email='', password='', confirm='',subscribe=False ): + def create( self, trans, email='', password='', confirm='', subscribe=False ): if trans.app.memory_usage: # Keep track of memory usage m0 = trans.app.memory_usage.memory() + if trans.app.config.require_login: + refresh_frames = [ 'masthead', 'history', 'tools' ] + else: + refresh_frames = [ 'masthead', 'history' ] + if not trans.app.config.allow_user_creation and not trans.user_is_admin(): + return trans.show_error_message( 'User registration is disabled. Please contact your local Galaxy administrator for an account.' ) email_error = password_error = confirm_error = None if email: if len( email ) == 0 or "@" not in email or "." not in email: @@ -130,29 +162,36 @@ class User( BaseController ): user = trans.app.model.User( email=email ) user.set_password_cleartext( password ) user.flush() - trans.app.security_agent.setup_new_user( user ) - trans.handle_user_login( user ) - trans.log_event( "User created a new account" ) - trans.log_event( "User logged in" ) + if trans.user_is_admin(): + trans.app.security_agent.create_private_user_role( user ) + trans.app.security_agent.user_set_default_permissions( user ) + trans.log_event( "Admin created a new account" ) + msg = 'Created account ' + user.email + else: + trans.app.security_agent.setup_new_user( user ) + trans.handle_user_login( user ) + trans.log_event( "User created a new account" ) + trans.log_event( "User logged in" ) + msg = 'Now logged in as ' + user.email #subscribe user to email list if subscribe: mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w') mail.write("To: %s\nFrom: %s\nSubject: Join Mailing List\n\nJoin Mailing list." % (trans.app.config.mailing_join_addr,email) ) if mail.close(): - return trans.show_warn_message( "Now logged in as " + user.email+". However, subscribing to the mailing list has failed.", refresh_frames=['masthead', 'history'] ) + return trans.show_warn_message( msg + ". However, subscribing to the mailing list has failed.", refresh_frames=refresh_frames ) if trans.app.memory_usage: m1 = trans.app.memory_usage.memory( m0, pretty=True ) log.info( "End of user/create, memory used increased by %s" % m1 ) - return trans.show_ok_message( "Now logged in as " + user.email, refresh_frames=['masthead', 'history'] ) + return trans.show_ok_message( msg, refresh_frames=refresh_frames ) return trans.show_form( web.FormBuilder( web.url_for(), "Create account", submit_text="Create" ) .add_text( "email", "Email address", value=email, error=email_error ) - .add_password( "password", "Password", value='', error=password_error ) - .add_password( "confirm", "Confirm password", value='', error=confirm_error ) + .add_password( "password", "Password", value='', error=password_error ) + .add_password( "confirm", "Confirm password", value='', error=confirm_error ) .add_input( "checkbox","Subscribe To Mailing List","subscribe", value='subscribe' ) ) @web.expose - def reset_password(self, trans, email=None, **kwd): + def reset_password( self, trans, email=None, **kwd ): error = '' reset_user = trans.app.model.User.filter_by( email=email ).first() user = trans.get_user() @@ -167,11 +206,11 @@ class User( BaseController ): mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w') mail.write("To: %s\nFrom: no-reply@%s\nSubject: Galaxy Password Reset\n\nYour password has been reset to \"%s\" (no quotes)." % (email, trans.request.remote_addr, new_pass) ) if mail.close(): - return trans.show_ok_message( "Failed to reset password! If this problem persist, submit a bug report.") + return trans.show_error_message( 'Failed to reset password. If this problem persists, please submit a bug report.' ) reset_user.set_password_cleartext( new_pass ) reset_user.flush() trans.log_event( "User reset password: %s" % email ) - return trans.show_ok_message( "Password has been reset and emailed to: %s." % email) + return trans.show_ok_message( "Password has been reset and emailed to: %s. Click here to return to the login form." % ( email, web.url_for( action='login' ) ) ) elif email != None: error = "The specified user does not exist" return trans.show_form( diff --git a/lib/galaxy/web/framework/__init__.py b/lib/galaxy/web/framework/__init__.py index c415c9c023c..ff51ec616c1 100644 --- a/lib/galaxy/web/framework/__init__.py +++ b/lib/galaxy/web/framework/__init__.py @@ -60,6 +60,19 @@ def require_login( verb="perform this action" ): return decorator return argcatcher +def require_admin( func ): + def decorator( self, trans, *args, **kwargs ): + admin_users = trans.app.config.get( "admin_users", "" ).split( "," ) + if not admin_users: + return trans.show_error_message( "You must be an administrator to access this feature, and no administrators are set in the Galaxy configuration." ) + user = trans.get_user() + if not user: + return trans.show_error_message( "You must be an administrator to access this feature, and currently you are not logged in." ) + if not user.email in admin_users: + return trans.show_error_message( "You must be an administrator to access this feature." ) + return func( self, trans, *args, **kwargs ) + return decorator + NOT_SET = object() class MessageException( Exception ): @@ -117,6 +130,8 @@ class UniverseWebTransaction( base.DefaultWebTransaction ): self.workflow_building_mode = False # Always have a valid galaxy session self.__ensure_valid_session() + if self.app.config.require_login: + self.__ensure_logged_in_user( environ ) @property def sa_session( self ): """ @@ -240,6 +255,18 @@ class UniverseWebTransaction( base.DefaultWebTransaction ): if prev_galaxy_session: objects_to_flush.append( prev_galaxy_session ) sa_session.flush( objects_to_flush ) + def __ensure_logged_in_user( self, environ ): + allowed_paths = ( + url_for( controller='root', action='index' ), + url_for( controller='root', action='tool_menu' ), + url_for( controller='root', action='masthead' ), + url_for( controller='root', action='history' ), + url_for( controller='user', action='login' ), + url_for( controller='user', action='create' ), + url_for( controller='user', action='reset_password' ), + ) + if self.galaxy_session.user is None and environ['PATH_INFO'] not in allowed_paths: + self.response.send_redirect( url_for( controller='root', action='index' ) ) def __create_new_session( self, prev_galaxy_session=None, user_for_new_session=None ): """ Create a new GalaxySession for this request, possibly with a connection @@ -369,7 +396,13 @@ class UniverseWebTransaction( base.DefaultWebTransaction ): self.galaxy_session.user = user self.sa_session.flush( [ self.galaxy_session ] ) user = property( get_user, set_user ) - + + def user_is_admin( self ): + admin_users = self.app.config.get( "admin_users", "" ).split( "," ) + if self.user and admin_users and self.user.email in admin_users: + return True + return False + def get_toolbox(self): """Returns the application toolbox""" return self.app.toolbox @@ -415,12 +448,12 @@ class UniverseWebTransaction( base.DefaultWebTransaction ): Convenience method for displaying an warn message. See `show_message`. """ return self.show_message( message, 'warning', refresh_frames ) - def show_form( self, form ): + def show_form( self, form, header=None ): """ Convenience method for displaying a simple page with a single HTML form. """ - return self.fill_template( "form.mako", form=form ) + return self.fill_template( "form.mako", form=form, header=header ) def fill_template(self, filename, **kwargs): """ Fill in a template, putting any keyword arguments on the context. diff --git a/lib/galaxy/web/framework/base.py b/lib/galaxy/web/framework/base.py index 6dff0719d2a..5bef6415223 100644 --- a/lib/galaxy/web/framework/base.py +++ b/lib/galaxy/web/framework/base.py @@ -84,15 +84,19 @@ class WebApplication( object ): friendly objects, finds the appropriate method to handle the request and calls it. """ - # Setup the transaction - trans = self.transaction_factory( environ ) # Map url using routes - path_info = trans.request.path_info + path_info = environ.get( 'PATH_INFO', '' ) map = self.mapper.match( path_info ) if map == None: raise httpexceptions.HTTPNotFound( "No route for " + path_info ) - # Save the complete mapper dict, we pop things off so they don't get passed down - raw_map = dict( map ) + # Setup routes + rc = routes.request_config() + rc.mapper = self.mapper + rc.mapper_dict = map + rc.environ = environ + # Setup the transaction + trans = self.transaction_factory( environ ) + rc.redirect = trans.response.send_redirect # Get the controller class controller_name = map.pop( 'controller', None ) controller = self.controllers.get( controller_name, None ) @@ -111,12 +115,6 @@ class WebApplication( object ): # Is the method callable if not callable( method ): raise httpexceptions.HTTPNotFound( "Action not callable for " + path_info ) - # Setup routes - rc = routes.request_config() - rc.mapper = self.mapper - rc.mapper_dict = raw_map - rc.environ = environ - rc.redirect = trans.response.send_redirect # Combine mapper args and query string / form args and call kwargs = trans.request.params.mixed() kwargs.update( map ) @@ -336,4 +334,4 @@ def flatten( seq ): for y in flatten( x, encoding ): yield y else: - yield x \ No newline at end of file + yield x diff --git a/static/scripts/galaxy.panels.js b/static/scripts/galaxy.panels.js index 7463991fbf9..efe2ccb0a2a 100644 --- a/static/scripts/galaxy.panels.js +++ b/static/scripts/galaxy.panels.js @@ -79,7 +79,12 @@ function make_left_panel( panel_el, center_el, border_el ) { } } ).find( "div" ).show();; - + var force_panel = function( op ) { + if ( ( hidden && op == 'show' ) || ( ! hidden && op == 'hide' ) ) { + toggle(); + } + } + return { force_panel: force_panel }; }; function make_right_panel( panel_el, center_el, border_el ) { @@ -173,7 +178,12 @@ function make_right_panel( panel_el, center_el, border_el ) { } } ).find( "div" ).show(); - return { handle_minwidth_hint: handle_minwidth_hint }; + var force_panel = function( op ) { + if ( ( hidden && op == 'show' ) || ( ! hidden && op == 'hide' ) ) { + toggle(); + } + } + return { handle_minwidth_hint: handle_minwidth_hint, force_panel: force_panel }; }; // Modal dialog boxes @@ -234,4 +244,4 @@ function make_popupmenu( button_element, options ) { } ); }; $( button_element ).click( click ); -}; \ No newline at end of file +}; diff --git a/static/scripts/packed/galaxy.panels.js b/static/scripts/packed/galaxy.panels.js index 241d997a112..fd71a3f43d6 100644 --- a/static/scripts/packed/galaxy.panels.js +++ b/static/scripts/packed/galaxy.panels.js @@ -1 +1 @@ -var hidden_width=7;var border_tweak=9;var jq=jQuery;function ensure_dd_helper(){if(jq("#DD-helper").length==0){$("

    ").css({background:"white",opacity:0,zIndex:9000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_left_panel(E,A,B){var D=false;var C=null;resize=function(F){var G=F;if(F<0){F=0}jq(E).css("width",F);jq(B).css("left",G);jq(A).css("left",F+7);if(document.recalc){document.recalc()}};toggle=function(){if(D){jq(B).removeClass("hover");jq(B).animate({left:C},"fast");jq(E).css("left",-C).show().animate({left:0},"fast",function(){resize(C);jq(B).removeClass("hidden")});D=false}else{C=jq(B).position().left;jq(A).css("left",hidden_width);if(document.recalc){document.recalc()}jq(B).removeClass("hover");jq(E).animate({left:-C},"fast");jq(B).animate({left:-1},"fast",function(){jq(this).addClass("hidden")});D=true}};jq(B).hover(function(){jq(this).addClass("hover")},function(){jq(this).removeClass("hover")}).draggable({start:function(F,G){jq("#DD-helper").show()},stop:function(F,G){jq("#DD-helper").hide();return false},drag:function(F,G){x=G.position.left;x=Math.min(400,Math.max(100,x));if(D){jq(E).css("left",0);jq(B).removeClass("hidden");D=false}resize(x);G.position.left=x;G.position.top=$(this).data("draggable").originalPosition.top},click:function(){toggle()}}).find("div").show()}function make_right_panel(A,E,G){var I=false;var F=false;var C=null;var D=function(J){jq(A).css("width",J);jq(E).css("right",J+9);jq(G).css("right",J).css("left","");if(document.recalc){document.recalc()}};var H=function(){if(I){jq(G).removeClass("hover");jq(G).animate({right:C},"fast");jq(A).css("right",-C).show().animate({right:0},"fast",function(){D(C);jq(G).removeClass("hidden")});I=false}else{C=jq(document).width()-jq(G).position().left-border_tweak;jq(E).css("right",hidden_width+1);if(document.recalc){document.recalc()}jq(G).removeClass("hover");jq(A).animate({right:-C},"fast");jq(G).animate({right:-1},"fast",function(){jq(this).addClass("hidden")});I=true}F=false};var B=function(J){var K=jq(E).width()-(I?C:0);if(K").text(F).click(G));A.append(" ")});A.show()}else{A.hide()}var A=$(".dialog-box").find(".extra_buttons").html("");if(C){$.each(C,function(F,G){A.append($("