galaxy-commits
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: dan: HTML escape user-settable values in Data Libraries. Update tests to reflect that e.g. quotes are now html escaped within pages. Eliminate the unnecessary use of Params() object for these controllers.
by commits-noreply@bitbucket.org 08 Dec '14
by commits-noreply@bitbucket.org 08 Dec '14
08 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bfc3b5e52781/
Changeset: bfc3b5e52781
User: dan
Date: 2014-12-08 17:27:48+00:00
Summary: HTML escape user-settable values in Data Libraries. Update tests to reflect that e.g. quotes are now html escaped within pages. Eliminate the unnecessary use of Params() object for these controllers.
Affected #: 17 files
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 lib/galaxy/webapps/galaxy/controllers/library.py
--- a/lib/galaxy/webapps/galaxy/controllers/library.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library.py
@@ -3,7 +3,7 @@
from galaxy import web
from galaxy.model.orm import and_, not_, or_
from galaxy.web.base.controller import BaseUIController
-from galaxy.web.framework.helpers import grids
+from galaxy.web.framework.helpers import escape, grids
from library_common import get_comptypes, lucene_search, whoosh_search
@@ -79,7 +79,6 @@
@web.expose
def list( self, trans, **kwd ):
- params = util.Params( kwd )
# define app configuration for generic mako template
app = {
'jscript' : "galaxy.library"
@@ -91,10 +90,9 @@
@web.expose
def index( self, trans, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- default_action = params.get( 'default_action', None )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'done' ) )
+ default_action = kwd.get( 'default_action', None )
return trans.fill_template( "/library/index.mako",
default_action=default_action,
message=message,
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 lib/galaxy/webapps/galaxy/controllers/library_admin.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_admin.py
@@ -5,7 +5,7 @@
from galaxy import web
from galaxy.web.base.controller import BaseUIController
-from galaxy.web.framework.helpers import grids, time_ago
+from galaxy.web.framework.helpers import escape, grids, time_ago
from library_common import get_comptypes, lucene_search, whoosh_search
# from galaxy.model.orm import *
@@ -141,20 +141,19 @@
lddas=lddas,
show_deleted=show_deleted,
use_panels=use_panels,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
# Render the list view
return self.library_list_grid( trans, **kwd )
@web.expose
@web.require_admin
def create_library( self, trans, **kwd ):
- params = galaxy.util.Params( kwd )
- message = galaxy.util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- if params.get( 'create_library_button', False ):
- name = galaxy.util.restore_text( params.get( 'name', 'No name' ) )
- description = galaxy.util.restore_text( params.get( 'description', '' ) )
- synopsis = galaxy.util.restore_text( params.get( 'synopsis', '' ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ if kwd.get( 'create_library_button', False ):
+ name = kwd.get( 'name', 'No name' )
+ description = kwd.get( 'description', '' )
+ synopsis = kwd.get( 'synopsis', '' )
if synopsis in [ 'None', None ]:
synopsis = ''
library = trans.app.model.Library( name=name, description=description, synopsis=synopsis )
@@ -167,9 +166,9 @@
action='browse_library',
cntrller='library_admin',
id=trans.security.encode_id( library.id ),
- message=galaxy.util.sanitize_text( message ),
+ message=message,
status='done' ) )
- return trans.fill_template( '/admin/library/new_library.mako', message=message, status=status )
+ return trans.fill_template( '/admin/library/new_library.mako', message=escape( message ), status=escape( status ) )
@web.expose
@web.require_admin
def delete_library( self, trans, id, **kwd ):
@@ -196,8 +195,7 @@
# TODO: change this function to purge_library_item, behaving similar to delete_library_item
# assuming we want the ability to purge libraries.
# This function is currently only used by the functional tests.
- params = galaxy.util.Params( kwd )
- library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( params.id ) )
+ library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( kwd.get( 'id' ) ) )
def purge_folder( library_folder ):
for lf in library_folder.folders:
purge_folder( lf )
@@ -226,7 +224,7 @@
message = "Library '%s' has not been marked deleted, so it cannot be purged" % ( library.name )
return trans.response.send_redirect( web.url_for( controller='library_admin',
action='browse_libraries',
- message=galaxy.util.sanitize_text( message ),
+ message=message,
status='error' ) )
else:
purge_folder( library.root_folder )
@@ -236,5 +234,5 @@
message = "Library '%s' and all of its contents have been purged, datasets will be removed from disk via the cleanup_datasets script" % library.name
return trans.response.send_redirect( web.url_for( controller='library_admin',
action='browse_libraries',
- message=galaxy.util.sanitize_text( message ),
+ message=message,
status='done' ) )
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 lib/galaxy/webapps/galaxy/controllers/library_common.py
--- a/lib/galaxy/webapps/galaxy/controllers/library_common.py
+++ b/lib/galaxy/webapps/galaxy/controllers/library_common.py
@@ -20,6 +20,7 @@
from galaxy.util.streamball import StreamBall
from galaxy.web.base.controller import BaseUIController, UsesFormDefinitionsMixin, UsesExtendedMetadataMixin, UsesLibraryMixinItems
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, build_select_field
+from galaxy.web.framework.helpers import escape
from galaxy.model.orm import and_, eagerload_all
# Whoosh is compatible with Python 2.5+ Try to import Whoosh and set flag to indicate whether tool search is enabled.
@@ -92,14 +93,13 @@
@web.expose
def browse_library( self, trans, cntrller='library', **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
# If use_panels is True, the library is being accessed via an external link
# which did not originate from within the Galaxy instance, and the library will
# be displayed correctly with the mast head.
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- library_id = params.get( 'id', None )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ library_id = kwd.get( 'id', None )
if not library_id:
# To handle bots
message = "You must specify a library id."
@@ -116,9 +116,9 @@
message = "Invalid library id ( %s ) specified." % str( library_id )
status = 'error'
else:
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- created_ldda_ids = params.get( 'created_ldda_ids', '' )
- hidden_folder_ids = util.listify( params.get( 'hidden_folder_ids', '' ) )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ created_ldda_ids = kwd.get( 'created_ldda_ids', '' )
+ hidden_folder_ids = util.listify( kwd.get( 'hidden_folder_ids', '' ) )
if created_ldda_ids and not message:
message = "%d datasets are uploading in the background to the library '%s' (each is selected). " % \
( len( created_ldda_ids.split( ',' ) ), library.name )
@@ -137,8 +137,8 @@
show_deleted=show_deleted,
comptypes=comptypes,
current_user_roles=current_user_roles,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
else:
return trans.fill_template( 'library/common/browse_library.mako',
cntrller=cntrller,
@@ -149,45 +149,44 @@
show_deleted=show_deleted,
comptypes=comptypes,
current_user_roles=current_user_roles,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
except Exception, e:
message = 'Error attempting to display contents of library (%s): %s.' % ( str( library.name ), str( e ) )
status = 'error'
- default_action = params.get( 'default_action', None )
+ default_action = kwd.get( 'default_action', None )
return trans.response.send_redirect( web.url_for( use_panels=use_panels,
controller=cntrller,
action='browse_libraries',
default_action=default_action,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
@web.expose
def library_info( self, trans, cntrller, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
- library_id = params.get( 'id', None )
+ library_id = kwd.get( 'id', None )
try:
library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) )
except:
library = None
self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'library_info_button', False ):
+ if kwd.get( 'library_info_button', False ):
self._check_modify( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
old_name = library.name
- new_name = util.restore_text( params.get( 'name', 'No name' ) )
+ new_name = kwd.get( 'name', 'No name' )
if not new_name:
message = 'Enter a valid name'
status='error'
else:
- new_description = util.restore_text( params.get( 'description', '' ) )
- new_synopsis = util.restore_text( params.get( 'synopsis', '' ) )
+ new_description = kwd.get( 'description', '' )
+ new_synopsis = kwd.get( 'synopsis', '' )
if new_synopsis in [ None, 'None' ]:
new_synopsis = ''
library.name = new_name
@@ -205,7 +204,7 @@
use_panels=use_panels,
id=trans.security.encode_id( library.id ),
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
# See if we have any associated templates
info_association, inherited = library.get_info_association()
@@ -221,30 +220,29 @@
show_deleted=show_deleted,
info_association=info_association,
inherited=inherited,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def library_permissions( self, trans, cntrller, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
- library_id = params.get( 'id', None )
+ library_id = kwd.get( 'id', None )
try:
library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) )
except:
library = None
self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'update_roles_button', False ):
+ if kwd.get( 'update_roles_button', False ):
# The user clicked the Save button on the 'Associate With Roles' form
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, library, permissions )
trans.sa_session.refresh( library )
@@ -257,7 +255,7 @@
use_panels=use_panels,
id=trans.security.encode_id( library.id ),
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
roles = trans.app.security_agent.get_legitimate_roles( trans, library, cntrller )
all_roles = trans.app.security_agent.get_all_roles( trans, cntrller )
@@ -269,16 +267,15 @@
roles=roles,
all_roles=all_roles,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def create_folder( self, trans, cntrller, parent_id, library_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' )
current_user_roles = trans.get_current_user_roles()
try:
@@ -291,9 +288,9 @@
parent_library = parent_folder.parent_library
self._check_access( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted )
self._check_add( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'new_folder_button', False ) or cntrller == 'api':
- new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ),
- description=util.restore_text( params.description ) )
+ if kwd.get( 'new_folder_button', False ) or cntrller == 'api':
+ new_folder = trans.app.model.LibraryFolder( name=kwd.get( 'name', '' ),
+ description=kwd.get( 'description', '' ) )
# We are associating the last used genome build with folders, so we will always
# initialize a new folder with the first dbkey in genome builds list which is currently
# ? unspecified (?)
@@ -325,7 +322,7 @@
show_deleted=show_deleted,
info_association=info_association,
inherited=inherited,
- message=message,
+ message=escape( message ),
status='done' )
# If not inheritable info_association, redirect to the library.
message = "The new folder named '%s' has been added to the data library." % new_folder.name
@@ -337,7 +334,7 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
# We do not render any template widgets on creation pages since saving the info_association
# cannot occur before the associated item is saved.
@@ -347,16 +344,15 @@
library_id=library_id,
folder=parent_folder,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def folder_info( self, trans, cntrller, id, library_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -364,11 +360,11 @@
except:
folder = None
self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'rename_folder_button', False ):
+ if kwd.get( 'rename_folder_button', False ):
self._check_modify( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted )
old_name = folder.name
- new_name = util.restore_text( params.name )
- new_description = util.restore_text( params.description )
+ new_name = kwd.get( 'name', '' )
+ new_description = kwd.get( 'description', '' )
if not new_name:
message = 'Enter a valid name'
status='error'
@@ -385,7 +381,7 @@
id=id,
library_id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
# See if we have any associated templates
widgets = []
@@ -405,16 +401,15 @@
show_deleted=show_deleted,
info_association=info_association,
inherited=inherited,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def folder_permissions( self, trans, cntrller, id, library_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -423,14 +418,14 @@
folder = None
self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted )
self._check_manage( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'update_roles_button', False ):
+ if kwd.get( 'update_roles_button', False ):
# The user clicked the Save button on the 'Associate With Roles' form
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
if k != 'LIBRARY_ACCESS':
# LIBRARY_ACCESS is a special permission set only at the library level
# and it is not inherited.
- in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( int( x ) ) for x in util.listify( params.get( k + '_in', [] ) ) ]
+ in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( int( x ) ) for x in util.listify( kwd.get( k + '_in', [] ) ) ]
permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles
trans.app.security_agent.set_all_library_permissions( trans, folder, permissions )
trans.sa_session.refresh( folder )
@@ -442,7 +437,7 @@
id=trans.security.encode_id( folder.id ),
library_id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
# If the library is public all roles are legitimate, but if the library
# is restricted, only those roles associated with the LIBRARY_ACCESS
@@ -456,16 +451,15 @@
current_user_roles=current_user_roles,
roles=roles,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def ldda_edit_info( self, trans, cntrller, library_id, folder_id, id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -474,7 +468,7 @@
ldda = None
self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted )
self._check_modify( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted )
- dbkey = params.get( 'dbkey', '?' )
+ dbkey = kwd.get( 'dbkey', '?' )
if isinstance( dbkey, list ):
dbkey = dbkey[0]
file_formats = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ]
@@ -498,26 +492,26 @@
info_association, inherited = ldda.get_info_association()
if info_association and ( not( inherited ) or info_association.inheritable ):
widgets = ldda.get_template_widgets( trans )
- if params.get( 'change', False ):
+ if kwd.get( 'change', False ):
# The user clicked the Save button on the 'Change data type' form
if __ok_to_edit_metadata( ldda.id ):
- if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( params.datatype ).allow_datatype_change:
- trans.app.datatypes_registry.change_datatype( ldda, params.datatype )
+ if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( kwd.get( 'datatype' ) ).allow_datatype_change:
+ trans.app.datatypes_registry.change_datatype( ldda, kwd.get( 'datatype' ) )
trans.sa_session.flush()
message = "Data type changed for library dataset '%s'." % ldda.name
status = 'done'
else:
- message = "You are unable to change datatypes in this manner. Changing %s to %s is not allowed." % ( ldda.extension, params.datatype )
+ message = "You are unable to change datatypes in this manner. Changing %s to %s is not allowed." % ( ldda.extension, kwd.get( 'datatype' ) )
status = 'error'
else:
message = "This dataset is currently being used as input or output. You cannot change datatype until the jobs have completed or you have canceled them."
status = "error"
- elif params.get( 'save', False ):
+ elif kwd.get( 'save', False ):
# The user clicked the Save button on the 'Edit Attributes' form
old_name = ldda.name
- new_name = util.restore_text( params.get( 'name', '' ) )
- new_info = util.restore_text( params.get( 'info', '' ) )
- new_message = util.restore_text( params.get( 'message', '' ) )
+ new_name = kwd.get( 'name', '' )
+ new_info = kwd.get( 'info', '' )
+ new_message = kwd.get( 'message', '' )
if not new_name:
message = 'Enter a valid name'
status = 'error'
@@ -530,12 +524,12 @@
for name, spec in ldda.datatype.metadata_spec.items():
if spec.get("readonly"):
continue
- optional = params.get( "is_" + name, None )
+ optional = kwd.get( "is_" + name, None )
if optional and optional == 'true':
# optional element... == 'true' actually means it is NOT checked (and therefore ommitted)
setattr( ldda.metadata, name, None )
else:
- setattr( ldda.metadata, name, spec.unwrap( params.get ( name, None ) ) )
+ setattr( ldda.metadata, name, spec.unwrap( kwd.get( name, None ) ) )
ldda.metadata.dbkey = dbkey
ldda.datatype.after_setting_metadata( ldda )
message = "Attributes updated for library dataset '%s'." % ldda.name
@@ -544,7 +538,7 @@
message = "Attributes updated, but metadata could not be changed because this dataset is currently being used as input or output. You must cancel or wait for these jobs to complete before changing metadata."
status = 'warning'
trans.sa_session.flush()
- elif params.get( 'detect', False ):
+ elif kwd.get( 'detect', False ):
# The user clicked the Auto-detect button on the 'Edit Attributes' form
if __ok_to_edit_metadata( ldda.id ):
for name, spec in ldda.datatype.metadata_spec.items():
@@ -559,8 +553,8 @@
message = "This dataset is currently being used as input or output. You cannot change metadata until the jobs have completed or you have canceled them."
status = 'error'
trans.sa_session.flush()
- elif params.get( 'change_extended_metadata', False):
- em_string = util.restore_text( params.get("extended_metadata", "") )
+ elif kwd.get( 'change_extended_metadata', False):
+ em_string = kwd.get("extended_metadata", "" )
if len(em_string):
payload = None
try:
@@ -610,17 +604,16 @@
show_deleted=show_deleted,
info_association=info_association,
inherited=inherited,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def ldda_info( self, trans, cntrller, library_id, folder_id, id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- show_associated_hdas_and_lddas = util.string_as_bool( params.get( 'show_associated_hdas_and_lddas', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ show_associated_hdas_and_lddas = util.string_as_bool( kwd.get( 'show_associated_hdas_and_lddas', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) )
@@ -660,16 +653,15 @@
current_user_roles=current_user_roles,
info_association=info_association,
inherited=inherited,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def ldda_permissions( self, trans, cntrller, library_id, folder_id, id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
ids = util.listify( id )
lddas = []
libraries = []
@@ -693,7 +685,7 @@
id=library_id,
cntrller=cntrller,
use_panels=use_panels,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
# If access to the dataset is restricted, then use the roles associated with the DATASET_ACCESS permission to
# determine the legitimate roles. If the dataset is public, see if access to the library is restricted. If
@@ -706,7 +698,7 @@
roles = trans.app.security_agent.get_legitimate_roles( trans, library, cntrller )
else:
roles = trans.app.security_agent.get_legitimate_roles( trans, ldda.dataset, cntrller )
- if params.get( 'update_roles_button', False ):
+ if kwd.get( 'update_roles_button', False ):
# Dataset permissions
access_action = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_ACCESS.action )
manage_permissions_action = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS.action )
@@ -763,8 +755,8 @@
library_id=library_id,
roles=roles,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
if len( ids ) > 1:
# Ensure that the permissions across all library items are identical, otherwise we can't update them together.
check_list = []
@@ -789,7 +781,7 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
# Display permission form, permissions will be updated for all lddas simultaneously.
return trans.fill_template( "/library/common/ldda_permissions.mako",
@@ -799,32 +791,31 @@
library_id=library_id,
roles=roles,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def upload_library_dataset( self, trans, cntrller, library_id, folder_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- ldda_message = util.restore_text( params.get( 'ldda_message', '' ) )
- deleted = util.string_as_bool( params.get( 'deleted', False ) )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- replace_id = params.get( 'replace_id', None )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ ldda_message = kwd.get( 'ldda_message', '' )
+ deleted = util.string_as_bool( kwd.get( 'deleted', False ) )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ replace_id = kwd.get( 'replace_id', None )
replace_dataset = None
- upload_option = params.get( 'upload_option', 'upload_file' )
- if params.get( 'files_0|space_to_tab', False ):
- space_to_tab = params.get( 'files_0|space_to_tab', '' )
+ upload_option = kwd.get( 'upload_option', 'upload_file' )
+ if kwd.get( 'files_0|space_to_tab', False ):
+ space_to_tab = kwd.get( 'files_0|space_to_tab', '' )
else:
- space_to_tab = params.get( 'space_to_tab', '' )
- link_data_only = params.get( 'link_data_only', 'copy_files' )
- dbkey = params.get( 'dbkey', '?' )
+ space_to_tab = kwd.get( 'space_to_tab', '' )
+ link_data_only = kwd.get( 'link_data_only', 'copy_files' )
+ dbkey = kwd.get( 'dbkey', '?' )
if isinstance( dbkey, list ):
last_used_build = dbkey[0]
else:
last_used_build = dbkey
- roles = params.get( 'roles', '' )
+ roles = kwd.get( 'roles', '' )
is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' )
current_user_roles = trans.get_current_user_roles()
widgets = []
@@ -853,7 +844,7 @@
library = folder.parent_library
if folder and last_used_build in [ 'None', None, '?' ]:
last_used_build = folder.genome_build
- if params.get( 'runtool_btn', False ) or params.get( 'ajax_upload', False ) or cntrller == 'api':
+ if kwd.get( 'runtool_btn', False ) or kwd.get( 'ajax_upload', False ) or cntrller == 'api':
error = False
if upload_option == 'upload_paths' and not trans.app.config.allow_library_path_paste:
error = True
@@ -878,7 +869,7 @@
replace_id=replace_id,
upload_option=upload_option,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
else:
# See if we have any inherited templates.
@@ -892,7 +883,7 @@
for index, widget_dict in enumerate( widgets ):
widget = widget_dict[ 'widget' ]
if isinstance( widget, AddressField ):
- value = util.restore_text( params.get( widget.name, '' ) )
+ value = kwd.get( widget.name, '' )
if value == 'new':
if self.field_param_values_ok( widget.name, 'AddressField', **kwd ):
# Save the new address
@@ -975,7 +966,7 @@
default_action=default_action,
created_ldda_ids=created_ldda_ids,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
else:
created_ldda_ids = ''
@@ -990,7 +981,7 @@
id=library_id,
created_ldda_ids=created_ldda_ids,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
# Note: if the upload form was submitted due to refresh_on_change for a form field, we cannot re-populate
# the field for the selected file ( files_0|file_data ) if the user selected one. This is because the value
@@ -1049,8 +1040,8 @@
link_data_only=link_data_only,
show_deleted=show_deleted,
ldda_message=ldda_message,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
def upload_dataset( self, trans, cntrller, library_id, folder_id, replace_dataset=None, **kwd ):
# Set up the traditional tool state/params
@@ -1064,16 +1055,15 @@
if input.type == "upload_dataset":
dataset_upload_inputs.append( input )
# Library-specific params
- params = util.Params( kwd ) # is this filetoolparam safe?
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- server_dir = util.restore_text( params.get( 'server_dir', '' ) )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ server_dir = kwd.get( 'server_dir', '' )
if replace_dataset not in [ None, 'None' ]:
replace_id = trans.security.encode_id( replace_dataset.id )
else:
replace_id = None
- upload_option = params.get( 'upload_option', 'upload_file' )
+ upload_option = kwd.get( 'upload_option', 'upload_file' )
response_code = 200
if upload_option == 'upload_directory':
if server_dir in [ None, 'None', '' ]:
@@ -1102,7 +1092,7 @@
try:
# FIXME: instead of passing params here ( which have been processed by util.Params(), the original kwd
# should be passed so that complex objects that may have been included in the initial request remain.
- library_bunch = upload_common.handle_library_params( trans, params, folder_id, replace_dataset )
+ library_bunch = upload_common.handle_library_params( trans, kwd, folder_id, replace_dataset )
except:
response_code = 500
message = "Unable to parse upload parameters, please report this error."
@@ -1113,9 +1103,9 @@
tool_params = upload_common.persist_uploads( tool_params )
uploaded_datasets = upload_common.get_uploaded_datasets( trans, cntrller, tool_params, precreated_datasets, dataset_upload_inputs, library_bunch=library_bunch )
elif upload_option == 'upload_directory':
- uploaded_datasets, response_code, message = self.get_server_dir_uploaded_datasets( trans, cntrller, params, full_dir, import_dir_desc, library_bunch, response_code, message )
+ uploaded_datasets, response_code, message = self.get_server_dir_uploaded_datasets( trans, cntrller, kwd, full_dir, import_dir_desc, library_bunch, response_code, message )
elif upload_option == 'upload_paths':
- uploaded_datasets, response_code, message = self.get_path_paste_uploaded_datasets( trans, cntrller, params, library_bunch, response_code, message )
+ uploaded_datasets, response_code, message = self.get_path_paste_uploaded_datasets( trans, cntrller, kwd, library_bunch, response_code, message )
upload_common.cleanup_unused_precreated_datasets( precreated_datasets )
if upload_option == 'upload_file' and not uploaded_datasets:
response_code = 400
@@ -1131,7 +1121,7 @@
replace_id=replace_id,
upload_option=upload_option,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
json_file_path = upload_common.create_paramfile( trans, uploaded_datasets )
data_list = [ ud.data for ud in uploaded_datasets ]
@@ -1146,7 +1136,7 @@
def make_library_uploaded_dataset( self, trans, cntrller, params, name, path, type, library_bunch, in_folder=None ):
link_data_only = params.get( 'link_data_only', 'copy_files' )
uuid_str = params.get( 'uuid', None )
- file_type = params.file_type
+ file_type = params.get( 'file_type' )
library_bunch.replace_dataset = None # not valid for these types of upload
uploaded_dataset = util.bunch.Bunch()
new_name = name
@@ -1162,8 +1152,8 @@
uploaded_dataset.type = type
uploaded_dataset.ext = None
uploaded_dataset.file_type = file_type
- uploaded_dataset.dbkey = params.dbkey
- uploaded_dataset.space_to_tab = params.space_to_tab
+ uploaded_dataset.dbkey = params.get( 'dbkey' )
+ uploaded_dataset.space_to_tab = params.get( 'space_to_tab' )
if in_folder:
uploaded_dataset.in_folder = in_folder
uploaded_dataset.data = upload_common.new_upload( trans, cntrller, uploaded_dataset, library_bunch )
@@ -1262,7 +1252,7 @@
return files_and_folders
def _paths_list(self, params):
- return [ (l.strip(), os.path.abspath(l.strip())) for l in params.filesystem_paths.splitlines() if l.strip() ]
+ return [ (l.strip(), os.path.abspath(l.strip())) for l in params.get( 'filesystem_paths', '' ).splitlines() if l.strip() ]
def _check_path_paste_params(self, params):
if params.get( 'filesystem_paths', '' ) == '':
@@ -1274,33 +1264,32 @@
if not os.path.exists( path ):
bad_paths.append( path )
if bad_paths:
- message = "Invalid paths:<br><ul><li>%s</li></ul>" % "</li><li>".join( bad_paths )
+ message = 'Invalid paths: "%s".' % '", "'.join( bad_paths )
response_code = 400
return None, response_code, message
return None
@web.expose
def add_history_datasets_to_library( self, trans, cntrller, library_id, folder_id, hda_ids='', **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- ldda_message = util.restore_text( params.get( 'ldda_message', '' ) )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- replace_id = params.get( 'replace_id', None )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ ldda_message = kwd.get( 'ldda_message', '' )
+ show_deleted = kwd.get( 'show_deleted', False )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ replace_id = kwd.get( 'replace_id', None )
replace_dataset = None
- upload_option = params.get( 'upload_option', 'import_from_history' )
- if params.get( 'files_0|space_to_tab', False ):
- space_to_tab = params.get( 'files_0|space_to_tab', '' )
+ upload_option = kwd.get( 'upload_option', 'import_from_history' )
+ if kwd.get( 'files_0|space_to_tab', False ):
+ space_to_tab = kwd.get( 'files_0|space_to_tab', '' )
else:
- space_to_tab = params.get( 'space_to_tab', '' )
- link_data_only = params.get( 'link_data_only', 'copy_files' )
- dbkey = params.get( 'dbkey', '?' )
+ space_to_tab = kwd.get( 'space_to_tab', '' )
+ link_data_only = kwd.get( 'link_data_only', 'copy_files' )
+ dbkey = kwd.get( 'dbkey', '?' )
if isinstance( dbkey, list ):
last_used_build = dbkey[0]
else:
last_used_build = dbkey
- roles = params.get( 'roles', '' )
+ roles = kwd.get( 'roles', '' )
is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' )
current_user_roles = trans.get_current_user_roles()
widgets = []
@@ -1338,9 +1327,9 @@
cntrller=cntrller,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
- if params.get( 'add_history_datasets_to_library_button', False ):
+ if kwd.get( 'add_history_datasets_to_library_button', False ):
hda_ids = util.listify( hda_ids )
if hda_ids:
dataset_names = []
@@ -1369,7 +1358,7 @@
trans.app.security_agent.copy_library_permissions( trans, folder, ldda )
trans.app.security_agent.copy_library_permissions( trans, folder, ldda.library_dataset )
else:
- library_bunch = upload_common.handle_library_params( trans, params, folder_id, replace_dataset )
+ library_bunch = upload_common.handle_library_params( trans, kwd, folder_id, replace_dataset )
if library_bunch.template and library_bunch.template_field_contents:
# Since information templates are inherited, the template fields can be displayed on the upload form.
# If the user has added field contents, we'll need to create a new form_values and info_association
@@ -1437,12 +1426,12 @@
id=library_id,
created_ldda_ids=created_ldda_ids,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
else:
message = 'Select at least one dataset from the list of active datasets in your current history'
status = 'error'
- upload_option = params.get( 'upload_option', 'import_from_history' )
+ upload_option = kwd.get( 'upload_option', 'import_from_history' )
widgets = self._get_populated_widgets( folder )
# Send list of data formats to the upload form so the "extension" select list can be populated dynamically
file_formats = trans.app.datatypes_registry.upload_file_formats
@@ -1476,8 +1465,8 @@
link_data_only=link_data_only,
show_deleted=show_deleted,
ldda_message=ldda_message,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
def _build_roles_select_list( self, trans, cntrller, library, selected_role_ids=[] ):
# Get the list of legitimate roles to display on the upload form. If the library is public,
@@ -1540,8 +1529,7 @@
def download_dataset_from_folder( self, trans, cntrller, id, library_id=None, **kwd ):
"""Catches the dataset id and displays file contents as directed"""
show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
- params = util.Params( kwd )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -1574,16 +1562,15 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
@web.expose
def library_dataset_info( self, trans, cntrller, id, library_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -1591,11 +1578,11 @@
except:
library_dataset = None
self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'edit_attributes_button', False ):
+ if kwd.get( 'edit_attributes_button', False ):
self._check_modify( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted )
old_name = library_dataset.name
- new_name = util.restore_text( params.get( 'name', '' ) )
- new_info = util.restore_text( params.get( 'info', '' ) )
+ new_name = kwd.get( 'name', '' )
+ new_info = kwd.get( 'info', '' )
if not new_name:
message = 'Enter a valid name'
status = 'error'
@@ -1624,16 +1611,15 @@
widgets=widgets,
widget_fields_have_contents=widget_fields_have_contents,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def library_dataset_permissions( self, trans, cntrller, id, library_id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
current_user_roles = trans.get_current_user_roles()
try:
@@ -1642,7 +1628,7 @@
library_dataset = None
self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted )
self._check_manage( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted )
- if params.get( 'update_roles_button', False ):
+ if kwd.get( 'update_roles_button', False ):
# The user clicked the Save button on the 'Associate With Roles' form
permissions = {}
for k, v in trans.app.model.Library.permitted_actions.items():
@@ -1673,23 +1659,22 @@
roles=roles,
current_user_roles=current_user_roles,
show_deleted=show_deleted,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def make_library_item_public( self, trans, cntrller, library_id, item_type, id, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
current_user_roles = trans.get_current_user_roles()
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
if item_type == 'library':
library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( id ) )
self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted )
- contents = util.string_as_bool( params.get( 'contents', 'False' ) )
+ contents = util.string_as_bool( kwd.get( 'contents', 'False' ) )
trans.app.security_agent.make_library_public( library, contents=contents )
if contents:
message = "The data library (%s) and all its contents have been made publicly accessible." % library.name
@@ -1716,7 +1701,7 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
@web.expose
@@ -1741,12 +1726,11 @@
rval += '%s %i %s%s %s\r\n' % ( crc, size, self.url_base, quoted_fname, relpath )
return rval
# Perform an action on a list of library datasets.
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- action = params.get( 'do_action', None )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ action = kwd.get( 'do_action', None )
lddas = []
error = False
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
@@ -1761,7 +1745,7 @@
else:
if action in [ 'import_to_current_history', 'import_to_histories' ]:
new_kwd = {}
- if action == 'import_to_current_history':
+ if current_history is not None and action == 'import_to_current_history':
encoded_current_history_id = trans.security.encode_id( current_history.id )
selected_history_id = encoded_current_history_id
new_kwd[ 'do_action' ] = action
@@ -1832,7 +1816,7 @@
folder_id=folder_id,
id=",".join( encoded_ldda_ids ),
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
else:
message = "You are not authorized to manage permissions on any of the selected datasets."
@@ -1993,11 +1977,11 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
else:
# We arrived here from the library_dataset_search_results page, so redirect there.
- search_term = params.get( 'search_term', '' )
+ search_term = kwd.get( 'search_term', '' )
comptypes = get_comptypes( trans )
return trans.fill_template( '/library/common/library_dataset_search_results.mako',
cntrller=cntrller,
@@ -2007,8 +1991,8 @@
lddas=lddas,
show_deleted=show_deleted,
use_panels=use_panels,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def import_datasets_to_histories( self, trans, cntrller, library_id='', folder_id='', ldda_ids='', target_history_id='', target_history_ids='', new_history_name='', **kwd ):
@@ -2018,12 +2002,11 @@
# - a select list option for acting on multiple selected datasets within a library
# ( ldda_ids is a comma separated string of ldda ids )
# - a menu option for a library dataset search result set ( ldda_ids is a comma separated string of ldda ids )
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- action = params.get( 'do_action', None )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ action = kwd.get( 'do_action', None )
user = trans.get_user()
current_history = trans.get_history()
if library_id:
@@ -2042,7 +2025,7 @@
target_history_ids = set( [ trans.security.decode_id( target_history_id ) for target_history_id in target_history_ids if target_history_id ] )
elif target_history_id:
target_history_ids = [ trans.security.decode_id( target_history_id ) ]
- if params.get( 'import_datasets_to_histories_button', False ):
+ if kwd.get( 'import_datasets_to_histories_button', False ):
invalid_datasets = 0
if not ldda_ids or not ( target_history_ids or new_history_name ):
message = "You must provide one or more source library datasets and one or more target histories."
@@ -2106,11 +2089,13 @@
# to the lddas in order for the menu optin to be available.
ldda = trans.sa_session.query( trans.model.LibraryDatasetDatasetAssociation ).get( ldda_id )
source_lddas.append( ldda )
+ if current_history is None:
+ current_history = trans.get_history( create=True )
if current_history is not None:
target_histories = [ current_history ]
else:
target_histories = []
- message = 'You must have a history before you can import datasets. You can do this by <a href="%s" target="_top">loading the analysis interface</a>.' % url_for(controller='root')
+ message = 'You must have a history before you can import datasets. You can do this by loading the analysis interface.'
status = 'error'
if user:
target_histories = user.active_histories
@@ -2120,7 +2105,7 @@
action='browse_library',
cntrller=cntrller,
id=library_id,
- message=util.sanitize_text( message ),
+ message=message,
status=status ) )
return trans.fill_template( "/library/common/import_datasets_to_histories.mako",
cntrller=cntrller,
@@ -2134,16 +2119,15 @@
new_history_name=new_history_name,
show_deleted=show_deleted,
use_panels=use_panels,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def manage_template_inheritance( self, trans, cntrller, item_type, library_id, folder_id=None, ldda_id=None, **kwd ):
- params = util.Params( kwd )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' )
current_user_roles = trans.get_current_user_roles()
try:
@@ -2162,7 +2146,7 @@
cntrller=cntrller,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
info_association, inherited = item.get_info_association( restrict=True )
if info_association:
@@ -2181,7 +2165,7 @@
folder_id=folder_id,
id=id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='done' ) )
@web.expose
@@ -2193,11 +2177,10 @@
# 'ldda' and item_id is a comma separated string of ldda ids )
# - a menu option for a library dataset search result set ( item_type is 'ldda' and item_id is a
# comma separated string of ldda ids )
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) )
- use_panels = util.string_as_bool( params.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
make_target_current = util.string_as_bool( make_target_current )
is_admin = trans.user_is_admin() and cntrller == 'library_admin'
user = trans.get_user()
@@ -2211,14 +2194,14 @@
else:
# Request sent from the library_dataset_search_results page.
source_library = None
- target_library_id = params.get( 'target_library_id', '' )
+ target_library_id = kwd.get( 'target_library_id', '' )
if target_library_id not in [ '', 'none', None ]:
target_library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( target_library_id ) )
elif make_target_current:
target_library = source_library
else:
target_library = None
- target_folder_id = params.get( 'target_folder_id', '' )
+ target_folder_id = kwd.get( 'target_folder_id', '' )
if target_folder_id not in [ '', 'none', None ]:
target_folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( target_folder_id ) )
if target_library is None:
@@ -2233,7 +2216,7 @@
elif item_type == 'folder':
move_folder_id = item_id
move_folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( move_folder_id ) )
- if params.get( 'move_library_item_button', False ):
+ if kwd.get( 'move_library_item_button', False ):
if not ( move_ldda_ids or move_folder_id ) or target_folder_id in [ '', 'none', None ]:
message = "You must select a source folder or one or more source datasets, and a target folder."
status = 'error'
@@ -2397,8 +2380,8 @@
target_folder_id_select_field=target_folder_id_select_field,
show_deleted=show_deleted,
use_panels=use_panels,
- message=message,
- status=status )
+ message=escape( message ),
+ status=escape( status ) )
@web.expose
def delete_library_item( self, trans, cntrller, library_id, item_id, item_type, **kwd ):
@@ -2569,7 +2552,7 @@
action='browse_libraries',
cntrller=cntrller,
use_panels=use_panels,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
return trans.response.send_redirect( web.url_for( controller='library_common',
action='browse_library',
@@ -2577,7 +2560,7 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
def _check_add( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ):
@@ -2593,7 +2576,7 @@
use_panels=use_panels,
id=library_id,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
def _check_manage( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ):
@@ -2610,7 +2593,7 @@
id=library_id,
cntrller=cntrller,
use_panels=use_panels,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
# Deny access if the user is not an admin and does not have the LIBRARY_MANAGE permission.
if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, item ) ):
@@ -2622,7 +2605,7 @@
id=library_id,
cntrller=cntrller,
use_panels=use_panels,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
def _check_modify( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ):
@@ -2637,7 +2620,7 @@
id=library_id,
use_panels=use_panels,
show_deleted=show_deleted,
- message=util.sanitize_text( message ),
+ message=message,
status='error' ) )
# ---- Utility methods -------------------------------------------------------
@@ -2777,9 +2760,8 @@
def lucene_search( trans, cntrller, search_term, search_url, **kwd ):
"""Return display of results from a full-text lucene search of data libraries."""
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
full_url = "%s/find?%s" % ( search_url, urllib.urlencode( { "kwd" : search_term } ) )
response = urllib2.urlopen( full_url )
ldda_ids = util.json.loads( response.read() )[ "ids" ]
@@ -2789,9 +2771,8 @@
def whoosh_search( trans, cntrller, search_term, **kwd ):
"""Return display of results from a full-text whoosh search of data libraries."""
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
ok = True
if whoosh_search_enabled:
whoosh_index_dir = trans.app.config.whoosh_index_dir
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 templates/webapps/galaxy/library/common/browse_library.mako
--- a/templates/webapps/galaxy/library/common/browse_library.mako
+++ b/templates/webapps/galaxy/library/common/browse_library.mako
@@ -236,29 +236,29 @@
%if current_version and ( not ldda.library_dataset.deleted or show_deleted ):
<tr class="datasetRow"
%if parent is not None:
- parent="${parent}"
+ parent="${parent | h}"
%endif
- id="libraryItem-${ldda.id}">
+ id="libraryItem-${ldda.id | h}"><td style="padding-left: ${pad+20}px;">
- <input style="float: left;" type="checkbox" name="ldda_ids" id="${trans.security.encode_id( ldda.id )}" value="${trans.security.encode_id( ldda.id )}"
+ <input style="float: left;" type="checkbox" name="ldda_ids" id="${trans.security.encode_id( ldda.id ) | h}" value="${trans.security.encode_id( ldda.id ) | h}"
%if selected:
checked="checked"
%endif
/>
%if simple:
- <label for="${trans.security.encode_id( ldda.id )}">${ util.unicodify( ldda.name )}</label>
+ <label for="${trans.security.encode_id( ldda.id ) | h}">${ util.unicodify( ldda.name ) | h}</label>
%else:
- <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dataset-${ldda.id}-popup">
+ <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dataset-${ldda.id | h}-popup"><a class="view-info" href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">
%if ldda.library_dataset.deleted:
- <div class="libraryItem-error">${util.unicodify( ldda.name )}</div>
+ <div class="libraryItem-error">${util.unicodify( ldda.name ) | h}</div>
%else:
- ${util.unicodify( ldda.name )}
+ ${util.unicodify( ldda.name ) | h}
%endif
</a></div>
%if not library.deleted:
- <div popupmenu="dataset-${ldda.id}-popup">
+ <div popupmenu="dataset-${ldda.id | h}-popup">
%if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify:
<a class="action-button" href="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a><a class="action-button" href="${h.url_for( controller='library_common', action='move_library_item', cntrller=cntrller, item_type='ldda', item_id=trans.security.encode_id( ldda.id ), source_library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Move this dataset</a>
@@ -287,7 +287,7 @@
%endif
%if can_modify:
%if not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.deleted:
- <a class="action-button" confirm="Click OK to delete dataset '${util.unicodify( ldda.name )}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Delete this dataset</a>
+ <a class="action-button" confirm="Click OK to delete dataset '${util.unicodify( ldda.name ) | h}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Delete this dataset</a>
%elif not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.purged and ldda.library_dataset.deleted:
<a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Undelete this dataset</a>
%endif
@@ -298,10 +298,10 @@
</td>
% if not simple:
<td id="libraryItemInfo">${render_library_item_info( ldda )}</td>
- <td>${ldda.extension}</td>
+ <td>${ldda.extension | h}</td>
% endif
- <td>${ldda.create_time.strftime( trans.app.config.pretty_datetime_format )}</td>
- <td>${ldda.get_size( nice_size=True )}</td>
+ <td>${ldda.create_time.strftime( trans.app.config.pretty_datetime_format ) | h}</td>
+ <td>${ldda.get_size( nice_size=True ) | h}</td></tr><%
my_row = row_counter.count
@@ -355,28 +355,28 @@
%>
%if not root_folder and ( not folder.deleted or show_deleted ):
<% encoded_id = trans.security.encode_id( folder.id ) %>
- <tr id="folder-${encoded_id}" class="folderRow libraryOrFolderRow"
+ <tr id="folder-${encoded_id | h}" class="folderRow libraryOrFolderRow"
%if parent is not None:
- parent="${parent}"
+ parent="${parent | h}"
style="display: none;"
%endif
>
- <td style="padding-left: ${folder_pad}px;">
+ <td style="padding-left: ${folder_pad | h}px;"><input type="checkbox" class="folderCheckbox"/>
- <span class="expandLink folder-${encoded_id}-click">
- <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id}-popup">
- <a class="folder-${encoded_id}-click" href="javascript:void(0);">
+ <span class="expandLink folder-${encoded_id | h}-click">
+ <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id | h}-popup">
+ <a class="folder-${encoded_id | h}-click" href="javascript:void(0);"><span class="rowIcon"></span>
%if folder.deleted:
- <div class="libraryItem-error">${folder.name}</div>
+ <div class="libraryItem-error">${folder.name | h}</div>
%else:
- ${folder.name}
+ ${folder.name | h}
%endif
</a></div></span>
%if not library.deleted:
- <div popupmenu="folder_img-${folder.id}-popup">
+ <div popupmenu="folder_img-${folder.id | h}-popup">
%if not branch_deleted( folder ) and can_add:
<a class="action-button" href="${h.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add datasets</a><a class="action-button" href="${h.url_for( controller='library_common', action='create_folder', cntrller=cntrller, parent_id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add sub-folder</a>
@@ -407,7 +407,7 @@
%endif
%if can_modify:
%if not library.deleted and not folder.deleted:
- <a class="action-button" confirm="Click OK to delete the folder '${folder.name}.'" href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Delete this folder</a>
+ <a class="action-button" confirm="Click OK to delete the folder '${folder.name | h}.'" href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Delete this folder</a>
%elif not library.deleted and folder.deleted and not folder.purged:
<a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Undelete this folder</a>
%endif
@@ -416,7 +416,7 @@
%endif
<td>
%if folder.description:
- ${folder.description}
+ ${folder.description | h}
%endif
<td colspan="3"></td></tr>
@@ -504,7 +504,7 @@
return str( self.count )
%>
- <h2>Data Library “${library.name}”</h2>
+ <h2>Data Library “${library.name | h}”</h2><ul class="manage-table-actions">
%if not library.deleted and ( is_admin or can_add ):
@@ -517,7 +517,7 @@
%if not library.deleted:
%if can_modify:
<a class="action-button" href="${h.url_for( controller='library_common', action='library_info', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a>
- <a class="action-button" confirm="Click OK to delete the library named '${library.name}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library' )}">Delete this data library</a>
+ <a class="action-button" confirm="Click OK to delete the library named '${library.name | h}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library' )}">Delete this data library</a>
%if show_deleted:
<a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=False )}">Hide deleted items</a>
%else:
@@ -555,7 +555,7 @@
%if library.synopsis not in [ '', 'None', None ]:
<div class="libraryItemBody">
- ${library.synopsis}
+ ${library.synopsis | h}
</div>
%endif
@@ -610,6 +610,6 @@
${render_compression_types_help( comptypes )}
%endif
%if not has_accessible_folders:
- The data library '${library.name}' does not contain any datasets that you can access.
+ The data library '${library.name | h}' does not contain any datasets that you can access.
%endif
</%def>
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 templates/webapps/galaxy/library/common/browse_library_opt.mako
--- a/templates/webapps/galaxy/library/common/browse_library_opt.mako
+++ b/templates/webapps/galaxy/library/common/browse_library_opt.mako
@@ -228,29 +228,29 @@
%if current_version and ( not ldda.library_dataset.deleted or show_deleted ):
<tr class="datasetRow"
%if parent is not None:
- parent="${parent}"
+ parent="${parent | h}"
%endif
- id="libraryItem-${ldda.id}">
+ id="libraryItem-${ldda.id | h}"><td style="padding-left: ${pad+20}px;">
- <input style="float: left;" type="checkbox" name="ldda_ids" id="${trans.security.encode_id( ldda.id )}" value="${trans.security.encode_id( ldda.id )}"
+ <input style="float: left;" type="checkbox" name="ldda_ids" id="${trans.security.encode_id( ldda.id ) | h}" value="${trans.security.encode_id( ldda.id ) | h}"
%if selected:
checked="checked"
%endif
/>
%if simple:
- <label for="${trans.security.encode_id( ldda.id )}">${ util.unicodify( ldda.name )}</label>
+ <label for="${trans.security.encode_id( ldda.id ) | h}">${ util.unicodify( ldda.name ) | h}</label>
%else:
- <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dataset-${ldda.id}-popup">
+ <div style="float: left; margin-left: 1px;" class="menubutton split popup" id="dataset-${ldda.id | h}-popup"><a class="view-info" href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">
%if ldda.library_dataset.deleted:
- <div class="libraryItem-error">${util.unicodify( ldda.name )}</div>
+ <div class="libraryItem-error">${util.unicodify( ldda.name ) | h}</div>
%else:
- ${util.unicodify( ldda.name )}
+ ${util.unicodify( ldda.name ) | h}
%endif
</a></div>
%if not library.deleted:
- <div popupmenu="dataset-${ldda.id}-popup">
+ <div popupmenu="dataset-${ldda.id | h}-popup">
%if not branch_deleted( folder ) and not ldda.library_dataset.deleted and can_modify:
<a class="action-button" href="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), id=trans.security.encode_id( ldda.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a><a class="action-button" href="${h.url_for( controller='library_common', action='move_library_item', cntrller=cntrller, item_type='ldda', item_id=trans.security.encode_id( ldda.id ), source_library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Move this dataset</a>
@@ -279,7 +279,7 @@
%endif
%if can_modify:
%if not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.deleted:
- <a class="action-button" confirm="Click OK to delete dataset '${util.unicodify( ldda.name )}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Delete this dataset</a>
+ <a class="action-button" confirm="Click OK to delete dataset '${util.unicodify( ldda.name ) | h}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Delete this dataset</a>
%elif not library.deleted and not branch_deleted( folder ) and not ldda.library_dataset.purged and ldda.library_dataset.deleted:
<a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library_dataset.id ), item_type='library_dataset', show_deleted=show_deleted )}">Undelete this dataset</a>
%endif
@@ -290,10 +290,10 @@
</td>
% if not simple:
<td id="libraryItemInfo">${render_library_item_info( ldda )}</td>
- <td>${ldda.extension}</td>
+ <td>${ldda.extension | h}</td>
% endif
- <td>${ldda.create_time.strftime( "%Y-%m-%d" )}</td>
- <td>${ldda.get_size( nice_size=True )}</td>
+ <td>${ldda.create_time.strftime( "%Y-%m-%d" ) | h}</td>
+ <td>${ldda.get_size( nice_size=True ) | h}</td></tr><%
my_row = row_counter.count
@@ -362,28 +362,28 @@
%>
%if not root_folder and ( not folder.deleted or show_deleted ):
<% encoded_id = trans.security.encode_id( folder.id ) %>
- <tr id="folder-${encoded_id}" class="folderRow libraryOrFolderRow"
+ <tr id="folder-${encoded_id | h}" class="folderRow libraryOrFolderRow"
%if parent is not None:
- parent="${parent}"
+ parent="${parent | h}"
style="display: none;"
%endif
>
- <td style="padding-left: ${folder_pad}px;">
+ <td style="padding-left: ${folder_pad | h}px;"><input type="checkbox" class="folderCheckbox"/>
- <span class="expandLink folder-${encoded_id}-click">
- <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id}-popup">
- <a class="folder-${encoded_id}-click" href="javascript:void(0);">
+ <span class="expandLink folder-${encoded_id | h}-click">
+ <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="folder_img-${folder.id | h}-popup">
+ <a class="folder-${encoded_id | h}-click" href="javascript:void(0);"><span class="rowIcon"></span>
%if folder.deleted:
- <div class="libraryItem-error">${folder.name}</div>
+ <div class="libraryItem-error">${folder.name | h}</div>
%else:
- ${folder.name}
+ ${folder.name | h}
%endif
</a></div></span>
%if not library.deleted:
- <div popupmenu="folder_img-${folder.id}-popup">
+ <div popupmenu="folder_img-${folder.id | h}-popup">
%if not branch_deleted( folder ) and can_add:
<a class="action-button" href="${h.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( folder.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add datasets</a><a class="action-button" href="${h.url_for( controller='library_common', action='create_folder', cntrller=cntrller, parent_id=trans.security.encode_id( folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add sub-folder</a>
@@ -414,7 +414,7 @@
%endif
%if can_modify:
%if not library.deleted and not folder.deleted:
- <a class="action-button" confirm="Click OK to delete the folder '${folder.name}.'" href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Delete this folder</a>
+ <a class="action-button" confirm="Click OK to delete the folder '${folder.name | h}.'" href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Delete this folder</a>
%elif not library.deleted and folder.deleted and not folder.purged:
<a class="action-button" href="${h.url_for( controller='library_common', action='undelete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( folder.id ), item_type='folder', show_deleted=show_deleted )}">Undelete this folder</a>
%endif
@@ -423,7 +423,7 @@
%endif
<td>
%if folder.description:
- ${folder.description}
+ ${folder.description | h}
%endif
<td colspan="3"></td></tr>
@@ -515,12 +515,12 @@
<li><a class="action-button" href="${h.url_for( controller='library_common', action='create_folder', cntrller=cntrller, parent_id=trans.security.encode_id( library.root_folder.id ), library_id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Add folder</a></li>
%endif
%if ( ( not library.deleted ) and ( can_modify or can_manage ) ) or ( can_modify and not library.purged ) or ( library.purged ):
- <li><a class="action-button" id="library-${library.id}-popup" class="menubutton">Library Actions</a></li>
- <div popupmenu="library-${library.id}-popup">
+ <li><a class="action-button" id="library-${library.id | h}-popup" class="menubutton">Library Actions</a></li>
+ <div popupmenu="library-${library.id | h}-popup">
%if not library.deleted:
%if can_modify:
<a class="action-button" href="${h.url_for( controller='library_common', action='library_info', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=show_deleted )}">Edit information</a>
- <a class="action-button" confirm="Click OK to delete the library named '${library.name}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library' )}">Delete this data library</a>
+ <a class="action-button" confirm="Click OK to delete the library named '${library.name | h}'." href="${h.url_for( controller='library_common', action='delete_library_item', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), item_id=trans.security.encode_id( library.id ), item_type='library' )}">Delete this data library</a>
%if show_deleted:
<a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( library.id ), use_panels=use_panels, show_deleted=False )}">Hide deleted items</a>
%else:
@@ -558,7 +558,7 @@
%if library.synopsis not in [ '', 'None', None ]:
<div class="libraryItemBody">
- ${library.synopsis}
+ ${library.synopsis | h}
</div>
%endif
@@ -616,6 +616,6 @@
${render_compression_types_help( comptypes )}
%endif
%if not has_accessible_folders:
- The data library '${library.name}' does not contain any datasets that you can access.
+ The data library '${library.name | h}' does not contain any datasets that you can access.
%endif
</%def>
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 templates/webapps/galaxy/library/common/common.mako
--- a/templates/webapps/galaxy/library/common/common.mako
+++ b/templates/webapps/galaxy/library/common/common.mako
@@ -88,19 +88,19 @@
else:
tool_form_title = 'Upload files'
%>
- <div class="toolFormTitle">${tool_form_title}</div>
+ <div class="toolFormTitle">${tool_form_title | h}</div><div class="toolFormBody"><form name="upload_library_dataset" id="upload_library_dataset" action="${action}" enctype="multipart/form-data" method="post"><input type="hidden" name="tool_id" value="upload1"/><input type="hidden" name="tool_state" value="None"/>
- <input type="hidden" name="cntrller" value="${cntrller}"/>
- <input type="hidden" name="library_id" value="${library_id}"/>
- <input type="hidden" name="folder_id" value="${folder_id}"/>
- <input type="hidden" name="show_deleted" value="${show_deleted}"/>
+ <input type="hidden" name="cntrller" value="${cntrller | h}"/>
+ <input type="hidden" name="library_id" value="${library_id | h}"/>
+ <input type="hidden" name="folder_id" value="${folder_id | h}"/>
+ <input type="hidden" name="show_deleted" value="${show_deleted | h}"/>
%if replace_dataset not in [ None, 'None' ]:
- <input type="hidden" name="replace_id" value="${trans.security.encode_id( replace_dataset.id )}"/>
+ <input type="hidden" name="replace_id" value="${trans.security.encode_id( replace_dataset.id ) | h}"/><div class="form-row">
- You are currently selecting a new file to replace '<a href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=library_id, folder_id=folder_id, id=trans.security.encode_id( replace_dataset.library_dataset_dataset_association.id ) )}">${util.unicodify( replace_dataset.name )}</a>'.
+ You are currently selecting a new file to replace '<a href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=library_id, folder_id=folder_id, id=trans.security.encode_id( replace_dataset.library_dataset_dataset_association.id ) )}">${util.unicodify( replace_dataset.name ) | h}</a>'.
<div style="clear: both"></div></div>
%endif
@@ -120,7 +120,7 @@
<select name="file_type"><option value="auto" selected>Auto-detect</option>
%for file_format in file_formats:
- <option value="${file_format}">${file_format}</option>
+ <option value="${file_format | h}">${file_format | h}</option>
%endfor
</select></div>
@@ -176,23 +176,23 @@
%for entry in os.listdir( import_dir ):
## Do not include entries that are not directories
%if os.path.isdir( os.path.join( import_dir, entry ) ):
- <option>${entry}</option>
+ <option>${entry | h}</option>
%endif
%endfor
%else:
%if ( trans.user_is_admin() and cntrller == 'library_admin' ):
- <option>${import_dir}</option>
+ <option>${import_dir | h}</option>
%else:
- <option>${trans.user.email}</option>
+ <option>${trans.user.email | h}</option>
%endif
%endif
</select></div><div class="toolParamHelp" style="clear: both;">
%if contains_directories:
- Upload all files in a sub-directory of <strong>${import_dir}</strong> on the Galaxy server.
+ Upload all files in a sub-directory of <strong>${import_dir | h}</strong> on the Galaxy server.
%else:
- Upload all files in <strong>${import_dir}</strong> on the Galaxy server.
+ Upload all files in <strong>${import_dir | h}</strong> on the Galaxy server.
%endif
</div><div style="clear: both"></div>
@@ -282,9 +282,9 @@
%>
%for dbkey in dbkeys:
%if dbkey[1] == default_selected:
- <option value="${dbkey[1]}" selected>${dbkey[0]}</option>
+ <option value="${dbkey[1] | h}" selected>${dbkey[0] | h}</option>
%else:
- <option value="${dbkey[1]}">${dbkey[0]}</option>
+ <option value="${dbkey[1] | h}">${dbkey[0] | h}</option>
%endif
%endfor
</select>
@@ -295,7 +295,7 @@
<label>Message:</label><div class="form-row-input">
%if ldda_message:
- <textarea name="ldda_message" rows="3" cols="35">${ldda_message}</textarea>
+ <textarea name="ldda_message" rows="3" cols="35">${ldda_message | h}</textarea>
%else:
<textarea name="ldda_message" rows="3" cols="35"></textarea>
%endif
@@ -320,13 +320,13 @@
%if widgets:
%for i, field in enumerate( widgets ):
<div class="form-row">
- <label>${field[ 'label' ]}</label>
+ <label>${field[ 'label' ] | h}</label><div class="form-row-input">
${field[ 'widget' ].get_html()}
</div><div class="toolParamHelp" style="clear: both;">
%if field[ 'helptext' ]:
- ${field[ 'helptext' ]}<br/>
+ ${field[ 'helptext' ] | h}<br/>
%endif
*Inherited template field
</div>
@@ -342,14 +342,14 @@
</div>
%elif upload_option == 'import_from_history':
<div class="toolForm">
- <div class="toolFormTitle">Active datasets in your current history (${ util.unicodify( history.name )})</div>
+ <div class="toolFormTitle">Active datasets in your current history (${ util.unicodify( history.name ) | h})</div><div class="toolFormBody">
%if history and history.active_datasets:
<form name="add_history_datasets_to_library" action="${h.url_for( controller='library_common', action='add_history_datasets_to_library', cntrller=cntrller, library_id=library_id )}" enctype="multipart/form-data" method="post">
- <input type="hidden" name="folder_id" value="${folder_id}"/>
- <input type="hidden" name="show_deleted" value="${show_deleted}"/>
+ <input type="hidden" name="folder_id" value="${folder_id | h}"/>
+ <input type="hidden" name="show_deleted" value="${show_deleted | h}"/><input type="hidden" name="upload_option" value="import_from_history"/>
- <input type="hidden" name="ldda_message" value="${ldda_message}"/>
+ <input type="hidden" name="ldda_message" value="${ldda_message | h}"/><%
role_ids_selected = ''
if roles_select_list:
@@ -357,32 +357,32 @@
if selected:
role_ids_selected = ','.join( selected )
%>
- <input type="hidden" name="roles" value="${role_ids_selected}"/>
+ <input type="hidden" name="roles" value="${role_ids_selected | h}"/>
%if replace_dataset not in [ None, 'None' ]:
- <input type="hidden" name="replace_id" value="${trans.security.encode_id( replace_dataset.id )}"/>
+ <input type="hidden" name="replace_id" value="${trans.security.encode_id( replace_dataset.id ) | h}"/><div class="form-row">
- You are currently selecting a new file to replace '<a href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=library_id, folder_id=folder_id, id=trans.security.encode_id( replace_dataset.library_dataset_dataset_association.id ) )}">${ util.unicodify( replace_dataset.name )}</a>'.
+ You are currently selecting a new file to replace '<a href="${h.url_for( controller='library_common', action='ldda_info', cntrller=cntrller, library_id=library_id, folder_id=folder_id, id=trans.security.encode_id( replace_dataset.library_dataset_dataset_association.id ) )}">${ util.unicodify( replace_dataset.name ) | h}</a>'.
<div style="clear: both"></div></div>
%endif
%for hda in history.visible_datasets:
<% encoded_id = trans.security.encode_id( hda.id ) %><div class="form-row">
- <input name="hda_ids" id="hist_${encoded_id}" value="${encoded_id}" type="checkbox"/>
- <label for="hist_${encoded_id}" style="display: inline;font-weight:normal;">${hda.hid}: ${ util.unicodify( hda.name )}</label>
+ <input name="hda_ids" id="hist_${encoded_id | h}" value="${encoded_id | h}" type="checkbox"/>
+ <label for="hist_${encoded_id | h}" style="display: inline;font-weight:normal;">${hda.hid | h}: ${ util.unicodify( hda.name ) | h}</label></div>
%endfor
%if widgets:
- <input type="hidden" name="template_id" value="${template_id}"/>
+ <input type="hidden" name="template_id" value="${template_id | h}"/>
%for i, field in enumerate( widgets ):
<div class="form-row">
- <label>${field[ 'label' ]}</label>
+ <label>${field[ 'label' ] | h}</label><div class="form-row-input">
${field[ 'widget' ].get_html()}
</div><div class="toolParamHelp" style="clear: both;">
%if field[ 'helptext' ]:
- ${field[ 'helptext' ]}<br/>
+ ${field[ 'helptext' ] | h}<br/>
%endif
*Inherited template field
</div>
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 templates/webapps/galaxy/library/common/import_datasets_to_histories.mako
--- a/templates/webapps/galaxy/library/common/import_datasets_to_histories.mako
+++ b/templates/webapps/galaxy/library/common/import_datasets_to_histories.mako
@@ -34,8 +34,8 @@
checked = " checked='checked'"
%><div class="form-row">
- <input type="checkbox" name="ldda_ids" id="dataset_${encoded_id}" value="${encoded_id}" ${checked}/>
- <label for="dataset_${encoded_id}" style="display: inline;font-weight:normal;">${util.unicodify( source_ldda.name )}</label>
+ <input type="checkbox" name="ldda_ids" id="dataset_${encoded_id | h}" value="${encoded_id | h}" ${checked}/>
+ <label for="dataset_${encoded_id | h}" style="display: inline;font-weight:normal;">${util.unicodify( source_ldda.name ) | h}</label></div>
%endfor
%else:
@@ -61,7 +61,7 @@
else:
current_history_text = ""
%>
- <option value="${encoded_id}"${selected_text}>${i + 1}: ${h.truncate( util.unicodify( target_history.name ), 30 )}${current_history_text}</option>
+ <option value="${encoded_id | h}"${selected_text}>${i + 1}: ${h.truncate( util.unicodify( target_history.name ), 30 ) | h}${current_history_text | h}</option>
%endfor
</select><br/><br/>
@@ -77,8 +77,8 @@
current_history_text = ""
%><div class="form-row">
- <input type="checkbox" name="target_history_ids" id="target_history_${encoded_id}" value="${encoded_id}"/>
- <label for="target_history_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${util.unicodify( target_history.name )}${current_history_text}</label>
+ <input type="checkbox" name="target_history_ids" id="target_history_${encoded_id | h}" value="${encoded_id | h}"/>
+ <label for="target_history_${encoded_id | h}" style="display: inline; font-weight:normal;">${i + 1}: ${util.unicodify( target_history.name ) | h}${current_history_text | h}</label></div>
%endfor
</div>
diff -r a8b8961827ec2475a20748f5151bd96c49566e98 -r bfc3b5e52781683efc8024f18c4aa57c65af1e15 templates/webapps/galaxy/library/common/ldda_edit_info.mako
--- a/templates/webapps/galaxy/library/common/ldda_edit_info.mako
+++ b/templates/webapps/galaxy/library/common/ldda_edit_info.mako
@@ -34,9 +34,9 @@
<select name="datatype">
%for ext in file_formats:
%if ldda.ext == ext:
- <option value="${ext}" selected="yes">${ext}</option>
+ <option value="${ext | h}" selected="yes">${ext | h}</option>
%else:
- <option value="${ext}">${ext}</option>
+ <option value="${ext | h}">${ext | h}</option>
%endif
%endfor
</select>
@@ -44,24 +44,24 @@
%if ( trans.user_is_admin() and cntrller=='library_admin' ) or trans.app.security_agent.can_modify_library_item( current_user_roles, ldda.library_dataset ):
<div class="toolForm">
- <div class="toolFormTitle">Edit attributes of ${util.unicodify( ldda.name )}</div>
+ <div class="toolFormTitle">Edit attributes of ${util.unicodify( ldda.name ) | h}</div><div class="toolFormBody"><form name="edit_attributes" action="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=library_id, folder_id=trans.security.encode_id( ldda.library_dataset.folder.id ), use_panels=use_panels, show_deleted=show_deleted, )}" method="post">
- <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id )}"/>
+ <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id ) | h}"/><div class="form-row"><label>Name:</label>
- <input type="text" name="name" value="${util.unicodify( ldda.name )}" size="40"/>
+ <input type="text" name="name" value="${util.unicodify( ldda.name ) | h}" size="40"/><div style="clear: both"></div></div><div class="form-row"><label>Info:</label>
- <input type="text" name="info" value="${util.unicodify( ldda.info )}" size="40"/>
+ <input type="text" name="info" value="${util.unicodify( ldda.info ) | h}" size="40"/><div style="clear: both"></div></div><div class="form-row"><label>Message:</label>
%if ldda.message:
- <textarea name="message" rows="3" cols="35">${ldda.message}</textarea>
+ <textarea name="message" rows="3" cols="35">${ldda.message | h}</textarea>
%else:
<textarea name="message" rows="3" cols="35"></textarea>
%endif
@@ -73,7 +73,7 @@
%for name, spec in ldda.metadata.spec.items():
%if spec.visible:
<div class="form-row">
- <label>${spec.desc}:</label>
+ <label>${spec.desc | h}:</label>
${ldda.metadata.get_html_by_name( name, trans=trans )}
<div style="clear: both"></div></div>
@@ -85,7 +85,7 @@
</form><form name="auto_detect" action="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=library_id, folder_id=trans.security.encode_id( ldda.library_dataset.folder.id ), use_panels=use_panels, show_deleted=show_deleted, )}" method="post"><div class="form-row">
- <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id )}"/>
+ <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id ) | h}"/><input type="submit" name="detect" value="Auto-detect"/><div class="toolParamHelp" style="clear: both;">
This will inspect the dataset and attempt to correct the above column values if they are not accurate.
@@ -101,7 +101,7 @@
%if ldda.datatype.allow_datatype_change:
<form name="change_datatype" action="${h.url_for( controller='library_common', action='ldda_edit_info', cntrller=cntrller, library_id=library_id, folder_id=trans.security.encode_id( ldda.library_dataset.folder.id ), use_panels=use_panels, show_deleted=show_deleted, )}" method="post"><div class="form-row">
- <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id )}"/>
+ <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id ) | h}"/><label>New Type:</label>
${datatype( ldda, file_formats )}
<div class="toolParamHelp" style="clear: both;">
@@ -129,10 +129,10 @@
<div class="form-row"><label>Extended Metadata:</label></div>
- <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id )}"/>
+ <input type="hidden" name="id" value="${trans.security.encode_id( ldda.id ) | h}"/><div class="form-row">
%if ldda.extended_metadata:
- <textarea name="extended_metadata" rows="15" cols="35">${util.pretty_print_json(ldda.extended_metadata.data)}</textarea>
+ <textarea name="extended_metadata" rows="15" cols="35">${util.pretty_print_json(ldda.extended_metadata.data) | h}</textarea>
%else:
<textarea name="extended_metadata" rows="15" cols="35"></textarea>
%endif
@@ -147,28 +147,28 @@
<p/>
%else:
<div class="toolForm">
- <div class="toolFormTitle">View information about ${util.unicodify( ldda.name )}</div>
+ <div class="toolFormTitle">View information about ${util.unicodify( ldda.name ) | h}</div><div class="toolFormBody"><div class="form-row"><label>Name:</label>
- ${util.unicodify( ldda.name )}
+ ${util.unicodify( ldda.name ) | h}
<div style="clear: both"></div></div><div class="form-row"><label>Info:</label>
- ${util.unicodify( ldda.info )}
+ ${util.unicodify( ldda.info ) | h}
<div style="clear: both"></div></div><div class="form-row"><label>Data Format:</label>
- ${ldda.ext}
+ ${ldda.ext | h}
<div style="clear: both"></div></div>
%for name, spec in ldda.metadata.spec.items():
%if spec.visible:
<div class="form-row">
- <label>${spec.desc}:</label>
- ${ldda.metadata.get( name )}
+ <label>${spec.desc | h}:</label>
+ ${ldda.metadata.get( name ) | h}
<div style="clear: both"></div></div>
%endif
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1c33c99c5250/
Changeset: 1c33c99c5250
Branch: stable
User: carlfeberhard
Date: 2014-11-25 19:22:08+00:00
Summary: Sanitize tag output in tagging_common and user.tags_used; protect against closing tags in bootstrapped JSON (http://benalpert.com/2012/08/03/preventing-xss-json.html) minor fixes
Affected #: 8 files
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa lib/galaxy/tags/tag_handler.py
--- a/lib/galaxy/tags/tag_handler.py
+++ b/lib/galaxy/tags/tag_handler.py
@@ -1,5 +1,7 @@
-import re, logging
-from sqlalchemy.sql.expression import func, and_
+import re
+import logging
+from sqlalchemy.sql.expression import func
+from sqlalchemy.sql.expression import and_
from sqlalchemy.sql import select
log = logging.getLogger( __name__ )
@@ -25,12 +27,15 @@
self.key_value_separators = "=:"
# Initialize with known classes - add to this in subclasses.
self.item_tag_assoc_info = {}
+
def get_tag_assoc_class( self, item_class ):
"""Returns tag association class for item class."""
return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class
+
def get_id_col_in_item_tag_assoc_table( self, item_class ):
"""Returns item id column in class' item-tag association table."""
return self.item_tag_assoc_info[item_class.__name__].item_id_col
+
def get_community_tags( self, trans, item=None, limit=None ):
"""Returns community tags for an item."""
# Get item-tag association class.
@@ -58,6 +63,7 @@
tag_id = row[0]
community_tags.append( self.get_tag_by_id( trans, tag_id ) )
return community_tags
+
def get_tool_tags( self, trans ):
result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ],
from_obj=trans.app.model.ToolTagAssociation.table ).distinct() )
@@ -67,6 +73,7 @@
tag_id = row[0]
tags.append( self.get_tag_by_id( trans, tag_id ) )
return tags
+
def remove_item_tag( self, trans, user, item, tag_name ):
"""Remove a tag from an item."""
# Get item tag association.
@@ -78,6 +85,7 @@
item.tags.remove( item_tag_assoc )
return True
return False
+
def delete_item_tags( self, trans, user, item ):
"""Delete tags from an item."""
# Delete item-tag associations.
@@ -85,6 +93,7 @@
trans.sa_session.delete( tag )
# Delete tags from item.
del item.tags[:]
+
def item_has_tag( self, trans, user, item, tag ):
"""Returns true if item is has a given tag."""
# Get tag name.
@@ -97,6 +106,7 @@
if item_tag_assoc:
return True
return False
+
def apply_item_tag( self, trans, user, item, name, value=None ):
# Use lowercase name for searching/creating tag.
lc_name = name.lower()
@@ -124,6 +134,7 @@
item_tag_assoc.user_value = value
item_tag_assoc.value = lc_value
return item_tag_assoc
+
def apply_item_tags( self, trans, user, item, tags_str ):
"""Apply tags to an item."""
# Parse tags.
@@ -131,6 +142,7 @@
# Apply each tag.
for name, value in parsed_tags.items():
self.apply_item_tag( trans, user, item, name, value )
+
def get_tags_str( self, tags ):
"""Build a string from an item's tags."""
# Return empty string if there are no tags.
@@ -144,14 +156,17 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
return ", ".join( tags_str_list )
+
def get_tag_by_id( self, trans, tag_id ):
"""Get a Tag object from a tag id."""
return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first()
+
def get_tag_by_name( self, trans, tag_name ):
"""Get a Tag object from a tag name (string)."""
if tag_name:
return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first()
return None
+
def _create_tag( self, trans, tag_str ):
"""Create a Tag object from a tag string."""
tag_hierarchy = tag_str.split( self.hierarchy_separator )
@@ -169,6 +184,7 @@
parent_tag = tag
tag_prefix = tag.name + self.hierarchy_separator
return tag
+
def _get_or_create_tag( self, trans, tag_str ):
"""Get or create a Tag object from a tag string."""
# Scrub tag; if tag is None after being scrubbed, return None.
@@ -181,6 +197,7 @@
if tag is None:
tag = self._create_tag( trans, scrubbed_tag_str )
return tag
+
def _get_item_tag_assoc( self, user, item, tag_name ):
"""
Return ItemTagAssociation object for a user, item, and tag string; returns None if there is
@@ -191,6 +208,7 @@
if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ):
return item_tag_assoc
return None
+
def parse_tags( self, tag_str ):
"""
Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well.
@@ -210,6 +228,7 @@
scrubbed_value = self._scrub_tag_value( nv_pair[1] )
name_value_pairs[scrubbed_name] = scrubbed_value
return name_value_pairs
+
def _scrub_tag_value( self, value ):
"""Scrub a tag value."""
# Gracefully handle None:
@@ -219,6 +238,7 @@
reg_exp = re.compile( '\s' )
scrubbed_value = re.sub( reg_exp, "", value )
return scrubbed_value
+
def _scrub_tag_name( self, name ):
"""Scrub a tag name."""
# Gracefully handle None:
@@ -234,12 +254,14 @@
if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len:
return None
return scrubbed_name
+
def _scrub_tag_name_list( self, tag_name_list ):
"""Scrub a tag name list."""
scrubbed_tag_list = list()
for tag in tag_name_list:
scrubbed_tag_list.append( self._scrub_tag_name( tag ) )
return scrubbed_tag_list
+
def _get_name_value_pair( self, tag_str ):
"""Get name, value pair from a tag string."""
# Use regular expression to parse name, value.
@@ -250,6 +272,7 @@
name_value_pair.append( None )
return name_value_pair
+
class GalaxyTagHandler( TagHandler ):
def __init__( self ):
from galaxy import model
@@ -271,6 +294,7 @@
model.VisualizationTagAssociation,
model.VisualizationTagAssociation.table.c.visualization_id )
+
class CommunityTagHandler( TagHandler ):
def __init__( self ):
from galaxy.webapps.tool_shed import model
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa lib/galaxy/util/json.py
--- a/lib/galaxy/util/json.py
+++ b/lib/galaxy/util/json.py
@@ -57,7 +57,7 @@
return val
-def safe_dumps(*args, **kwargs):
+def safe_dumps( *args, **kwargs ):
"""
This is a wrapper around dumps that encodes Infinity and NaN values. It's a
fairly rare case (which will be low in request volume). Basically, we tell
@@ -65,10 +65,12 @@
re-encoding.
"""
try:
- dumped = json.dumps(*args, allow_nan=False, **kwargs)
+ dumped = json.dumps( *args, allow_nan=False, **kwargs )
except ValueError:
- obj = swap_inf_nan(copy.deepcopy(args[0]))
- dumped = json.dumps(obj, allow_nan=False, **kwargs)
+ obj = swap_inf_nan( copy.deepcopy( args[0] ) )
+ dumped = json.dumps( obj, allow_nan=False, **kwargs )
+ if kwargs.get( 'escape_closing_tags', True ):
+ return dumped.replace( '</', '<\\/' )
return dumped
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa lib/galaxy/util/validation.py
--- a/lib/galaxy/util/validation.py
+++ b/lib/galaxy/util/validation.py
@@ -8,8 +8,8 @@
def validate_and_sanitize_basestring( key, val ):
if not isinstance( val, basestring ):
- raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
- % ( key, str( type( val ) ) ) )
+ raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
+ % ( key, str( type( val ) ) ) )
return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' )
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa lib/galaxy/web/framework/helpers/__init__.py
--- a/lib/galaxy/web/framework/helpers/__init__.py
+++ b/lib/galaxy/web/framework/helpers/__init__.py
@@ -111,4 +111,3 @@
Returns true if input is a boolean and true or is a string and looks like a true value.
"""
return val == True or val in [ 'True', 'true', 'T', 't' ]
-
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa lib/galaxy/webapps/galaxy/controllers/tag.py
--- a/lib/galaxy/webapps/galaxy/controllers/tag.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tag.py
@@ -64,7 +64,7 @@
trans.log_action( user, unicode( "untag" ), context, params )
# Retag an item. All previous tags are deleted and new tags are applied.
- #(a)web.expose
+ @web.expose
@web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ):
"""
@@ -73,7 +73,7 @@
# Apply tags.
item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
user = trans.user
- self.get_tag_handler( trans ).delete_item_tags( trans, item )
+ self.get_tag_handler( trans ).delete_item_tags( trans, user, item )
self.get_tag_handler( trans ).apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) )
trans.sa_session.flush()
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa templates/galaxy_client_app.mako
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -15,7 +15,7 @@
//TODO: global...
%for key in kwargs:
( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = (
- ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} );
+ ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ).replace( '</', '<\\/' ) } );
%endfor
define( 'bootstrapped-data', function(){
return window.bootstrapped;
@@ -76,11 +76,17 @@
user_dict = trans.user.to_dict( view='element',
value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } )
user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
+ user_dict[ 'is_admin' ] = trans.user_is_admin()
# tags used
users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
+ tags_used = []
+ for tag in users_api_controller.get_user_tags_used( trans, user=trans.user ):
+ tag = tag | h
+ if tag:
+ tags_used.append( tag )
+ user_dict[ 'tags_used' ] = tags_used
+
return user_dict
usage = 0
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa templates/tagging_common.mako
--- a/templates/tagging_common.mako
+++ b/templates/tagging_common.mako
@@ -19,7 +19,7 @@
## Render HTML for a list of tags.
<%def name="render_tagging_element_html(elt_id=None, tags=None, editable=True, use_toggle_link=True, input_size='15', in_form=False, tag_type='individual', render_add_tag_button=True)">
## Useful attributes.
- <%
+ <%
num_tags = len( tags )
%><div class="tag-element"
@@ -50,6 +50,7 @@
elif isinstance( tag, ItemTagAssociation ):
tag_name = tag.user_tname
tag_value = tag.user_value
+
## Convert tag name, value to unicode.
if isinstance( tag_name, str ):
tag_name = unicode( escape( tag_name ), 'utf-8' )
@@ -61,7 +62,7 @@
tag_str = tag_name
%><span class="tag-button">
- <span class="tag-name">${tag_str}</span>
+ <span class="tag-name">${tag_str | h}</span>
%if editable:
<img class="delete-tag-img" src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/>
%endif
@@ -186,10 +187,11 @@
## Build dict of tag name, values.
tag_names_and_values = dict()
for tag in item_tags:
- tag_name = tag.user_tname
+ tag_name = escape( tag.user_tname )
tag_value = ""
if tag.value is not None:
- tag_value = tag.user_value
+ tag_value = escape( tag.user_value )
+
## Tag names and values may be string or unicode object.
if isinstance( tag_name, str ):
tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8')
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -1,32 +1,4 @@
-## get user data
-<%def name="get_user_json()">
-<%
- """Bootstrapping user API JSON"""
- #TODO: move into common location (poss. BaseController)
- if trans.user:
- user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id,
- 'total_disk_usage': float } )
- user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
- users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
- else:
- usage = 0
- percent = None
- try:
- usage = trans.app.quota_agent.get_usage( trans, history=trans.history )
- percent = trans.app.quota_agent.get_percent( trans=trans, usage=usage )
- except AssertionError, assertion:
- # no history for quota_agent.get_usage assertion
- pass
- user_dict = {
- 'total_disk_usage' : int( usage ),
- 'nice_total_disk_usage' : util.nice_size( usage ),
- 'quota_percent' : percent
- }
- return user_dict
-%>
-</%def>
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## masthead head generator
<%def name="load(active_view = None)">
@@ -87,7 +59,7 @@
], function( mod_masthead, mod_menu, mod_modal, mod_frame, GalaxyUpload, user, quotameter ){
if( !Galaxy.currUser ){
// this doesn't need to wait for the page being readied
- Galaxy.currUser = new user.User(${ h.dumps( get_user_json(), indent=2 ) });
+ Galaxy.currUser = new user.User(${ h.dumps( masthead_config[ 'user' ][ 'json' ], indent=2 ) });
}
$(function() {
https://bitbucket.org/galaxy/galaxy-central/commits/07b0b60f17ee/
Changeset: 07b0b60f17ee
Branch: stable
User: carlfeberhard
Date: 2014-11-25 19:29:48+00:00
Summary: Fix to 04a072e98658: remove unnecessary replace
Affected #: 1 file
diff -r 1c33c99c5250533fd9b2e36748573d5ae6d23cfa -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 templates/galaxy_client_app.mako
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -15,7 +15,7 @@
//TODO: global...
%for key in kwargs:
( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = (
- ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ).replace( '</', '<\\/' ) } );
+ ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ) } );
%endfor
define( 'bootstrapped-data', function(){
return window.bootstrapped;
https://bitbucket.org/galaxy/galaxy-central/commits/374e94196a14/
Changeset: 374e94196a14
Branch: stable
User: carlfeberhard
Date: 2014-11-26 17:28:28+00:00
Summary: Security, UI: minor fixes to history, dataset, and page escaping; escape js tag and annotation displays
Affected #: 18 files
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 client/galaxy/scripts/mvc/annotations.js
--- a/client/galaxy/scripts/mvc/annotations.js
+++ b/client/galaxy/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 client/galaxy/scripts/mvc/tags.js
--- a/client/galaxy/scripts/mvc/tags.js
+++ b/client/galaxy/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 static/scripts/mvc/annotations.js
--- a/static/scripts/mvc/annotations.js
+++ b/static/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 static/scripts/mvc/tags.js
--- a/static/scripts/mvc/tags.js
+++ b/static/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 static/scripts/packed/mvc/annotations.js
--- a/static/scripts/packed/mvc/annotations.js
+++ b/static/scripts/packed/mvc/annotations.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',d,"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',_.escape(d),"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 static/scripts/packed/mvc/tags.js
--- a/static/scripts/packed/mvc/tags.js
+++ b/static/scripts/packed/mvc/tags.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.map(function(e){return _.escape(e)}).sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/copy_view.mako
--- a/templates/webapps/galaxy/dataset/copy_view.mako
+++ b/templates/webapps/galaxy/dataset/copy_view.mako
@@ -53,7 +53,7 @@
%><option value="${trans.security.encode_id(hist.id)}" ${selected}>
- ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30)}${current_history_text}
+ ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30) | h}${current_history_text}
</option>
%endfor
</select>
@@ -70,7 +70,7 @@
%><div class="form-row"><input type="checkbox" name="source_content_ids" id="${input_id}" value="${input_id}"${checked}/>
- <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name)}</label>
+ <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name) | h}</label></div>
%endfor
%else:
@@ -95,7 +95,7 @@
if encoded_id == target_history_id:
selected = " selected='selected'"
%>
- <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30)}${source_history_text}</option>
+ <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30) | h}${source_history_text}</option>
%endfor
</select><br /><br /><a style="margin-left: 10px;" href="javascript:void(0);" id="select-multiple">Choose multiple histories</a>
@@ -110,7 +110,7 @@
%><div class="form-row"><input type="checkbox" name="target_history_ids" id="hist_${encoded_id}" value="${encoded_id}"/>
- <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) }${cur_history_text}</label>
+ <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) | h }${cur_history_text}</label></div>
%endfor
</div>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/display.mako
--- a/templates/webapps/galaxy/dataset/display.mako
+++ b/templates/webapps/galaxy/dataset/display.mako
@@ -26,13 +26,11 @@
data.createTabularDatasetChunkedView({
// TODO: encode id.
dataset_config:
- _.extend( ${h.dumps( item.to_dict() )},
- {
- chunk_url: "${h.url_for( controller='/dataset', action='display',
- dataset_id=trans.security.encode_id( item.id ))}",
- first_data_chunk: ${first_chunk}
- }
- ),
+ _.extend( ${h.dumps( item.to_dict() )}, {
+ chunk_url: "${h.url_for( controller='/dataset', action='display',
+ dataset_id=trans.security.encode_id( item.id ))}",
+ first_data_chunk: ${first_chunk}
+ }),
parent_elt: $('.page-body')
});
});
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/embed.mako
--- a/templates/webapps/galaxy/dataset/embed.mako
+++ b/templates/webapps/galaxy/dataset/embed.mako
@@ -4,10 +4,13 @@
%><%def name="render_item_links( dataset )">
- <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}" title="Save dataset" class="icon-button disk"></a>
+ <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}"
+ title="Save dataset" class="icon-button disk"></a>
## Links for importing and viewing an item.
- <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}" title="Import dataset" class="icon-button import"></a>
- <a class="icon-button go-to-full-screen" href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}" title="Go to dataset"></a>
+ <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}"
+ title="Import dataset" class="icon-button import"></a>
+ <a href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}"
+ title="Go to dataset" class="icon-button go-to-full-screen"></a></%def>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -49,7 +49,7 @@
<body><h2>Dataset generation errors</h2>
- <p><b>Dataset ${hda.hid}: ${hda.display_name()}</b></p>
+ <p><b>Dataset ${hda.hid}: ${hda.display_name() | h}</b></p><% job = hda.creating_job %>
%if job:
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/security_common.mako
--- a/templates/webapps/galaxy/dataset/security_common.mako
+++ b/templates/webapps/galaxy/dataset/security_common.mako
@@ -77,7 +77,7 @@
else:
current_actions = []
permitted_actions = {}.items()
- obj_str = 'unknown object %s' %obj_name
+ obj_str = 'unknown object %s' % obj_name
obj_type = ''
%><script type="text/javascript">
@@ -104,7 +104,7 @@
});
</script><div class="toolForm">
- <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str}</div>
+ <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str | h}</div><div class="toolFormBody"><form name="edit_role_associations" id="edit_role_associations" action="${form_url}" method="post"><div class="form-row"></div>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/dataset/tabular_chunked.mako
--- a/templates/webapps/galaxy/dataset/tabular_chunked.mako
+++ b/templates/webapps/galaxy/dataset/tabular_chunked.mako
@@ -15,14 +15,12 @@
}
});
- require(['mvc/data'], function(data) {
+ require([ 'mvc/data' ], function( data ) {
data.createTabularDatasetChunkedView({
- dataset_config: _.extend( ${h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )},
- {
- first_data_chunk: ${chunk}
- }
- ),
- parent_elt: $('body')
+ dataset_config : _.extend( ${ h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )}, {
+ first_data_chunk: ${ chunk }
+ }),
+ parent_elt : $( 'body' )
});
});
</script>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/history/embed.mako
--- a/templates/webapps/galaxy/history/embed.mako
+++ b/templates/webapps/galaxy/history/embed.mako
@@ -24,7 +24,7 @@
</a></h4>
%if hasattr( item, "annotation") and item.annotation:
- <div class="annotation">${item.annotation}</div>
+ <div class="annotation">${item.annotation | h}</div>
%endif
</div><div class='summary-content'>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/history/history_panel.mako
--- a/templates/webapps/galaxy/history/history_panel.mako
+++ /dev/null
@@ -1,14 +0,0 @@
-## shortcuts for script tags that create history panels
-## ----------------------------------------------------------------------------
-<%def name="current_history_panel( selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="history_panel( history_id, selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="bootstrapped_history_panel( history, hdas, selector_to_attach_to=None, options )">
-</%def>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/history/share.mako
--- a/templates/webapps/galaxy/history/share.mako
+++ b/templates/webapps/galaxy/history/share.mako
@@ -20,7 +20,7 @@
<tr><td><input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
- ${ util.unicodify( history.name )}
+ ${ util.unicodify( history.name ) | h }
</td><td>
%if len( history.datasets ) < 1:
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -1,4 +1,4 @@
-<%namespace file="/galaxy.masthead.mako" import="get_user_json" />
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## ----------------------------------------------------------------------------
<%!
@@ -166,9 +166,9 @@
// use_panels effects where the the center_panel() is rendered:
// w/o it renders to the body, w/ it renders to #center - we need to adjust a few things for scrolling to work
var hasMasthead = ${ 'true' if use_panels else 'false' },
- userIsOwner = ${'true' if user_is_owner else 'false'},
- historyJSON = ${h.dumps( history )},
- hdaJSON = ${h.dumps( hdas )},
+ userIsOwner = ${ 'true' if user_is_owner else 'false' },
+ historyJSON = ${ h.dumps( history ) },
+ hdaJSON = ${ h.dumps( hdas ) },
panelToUse = ( userIsOwner )?
//TODO: change class names
({ location: 'mvc/history/history-panel-edit', className: 'HistoryPanelEdit' }):
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/page/editor.mako
--- a/templates/webapps/galaxy/page/editor.mako
+++ b/templates/webapps/galaxy/page/editor.mako
@@ -47,7 +47,7 @@
<a id="close-button" class="panel-header-button">Close</a></div><div class="unified-panel-header-inner">
- Page Editor <span style="font-weight: normal">| Title : ${page.title}</span>
+ Page Editor <span style="font-weight: normal">| Title : ${page.title | h}</span></div></div>
diff -r 07b0b60f17ee5ce4383029f1c98267284e6e0160 -r 374e94196a14673993540a60d446addc6b1780a0 templates/webapps/galaxy/page/index.mako
--- a/templates/webapps/galaxy/page/index.mako
+++ b/templates/webapps/galaxy/page/index.mako
@@ -30,7 +30,7 @@
<% page = association.page %><tr><td>
- <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title}</a>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title | h}</a></td><td>${page.user.username}</td><td>
https://bitbucket.org/galaxy/galaxy-central/commits/0c8ac7330cdd/
Changeset: 0c8ac7330cdd
Branch: stable
User: dannon
Date: 2014-12-08 16:44:52+00:00
Summary: Merged in carlfeberhard/carlfeberhard-galaxy-central-stable/stable (pull request #594)
[STABLE] Next-stable security fixes to stable.
Affected #: 26 files
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 client/galaxy/scripts/mvc/annotations.js
--- a/client/galaxy/scripts/mvc/annotations.js
+++ b/client/galaxy/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 client/galaxy/scripts/mvc/tags.js
--- a/client/galaxy/scripts/mvc/tags.js
+++ b/client/galaxy/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/tags/tag_handler.py
--- a/lib/galaxy/tags/tag_handler.py
+++ b/lib/galaxy/tags/tag_handler.py
@@ -1,5 +1,7 @@
-import re, logging
-from sqlalchemy.sql.expression import func, and_
+import re
+import logging
+from sqlalchemy.sql.expression import func
+from sqlalchemy.sql.expression import and_
from sqlalchemy.sql import select
log = logging.getLogger( __name__ )
@@ -25,12 +27,15 @@
self.key_value_separators = "=:"
# Initialize with known classes - add to this in subclasses.
self.item_tag_assoc_info = {}
+
def get_tag_assoc_class( self, item_class ):
"""Returns tag association class for item class."""
return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class
+
def get_id_col_in_item_tag_assoc_table( self, item_class ):
"""Returns item id column in class' item-tag association table."""
return self.item_tag_assoc_info[item_class.__name__].item_id_col
+
def get_community_tags( self, trans, item=None, limit=None ):
"""Returns community tags for an item."""
# Get item-tag association class.
@@ -58,6 +63,7 @@
tag_id = row[0]
community_tags.append( self.get_tag_by_id( trans, tag_id ) )
return community_tags
+
def get_tool_tags( self, trans ):
result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ],
from_obj=trans.app.model.ToolTagAssociation.table ).distinct() )
@@ -67,6 +73,7 @@
tag_id = row[0]
tags.append( self.get_tag_by_id( trans, tag_id ) )
return tags
+
def remove_item_tag( self, trans, user, item, tag_name ):
"""Remove a tag from an item."""
# Get item tag association.
@@ -78,6 +85,7 @@
item.tags.remove( item_tag_assoc )
return True
return False
+
def delete_item_tags( self, trans, user, item ):
"""Delete tags from an item."""
# Delete item-tag associations.
@@ -85,6 +93,7 @@
trans.sa_session.delete( tag )
# Delete tags from item.
del item.tags[:]
+
def item_has_tag( self, trans, user, item, tag ):
"""Returns true if item is has a given tag."""
# Get tag name.
@@ -97,6 +106,7 @@
if item_tag_assoc:
return True
return False
+
def apply_item_tag( self, trans, user, item, name, value=None ):
# Use lowercase name for searching/creating tag.
lc_name = name.lower()
@@ -124,6 +134,7 @@
item_tag_assoc.user_value = value
item_tag_assoc.value = lc_value
return item_tag_assoc
+
def apply_item_tags( self, trans, user, item, tags_str ):
"""Apply tags to an item."""
# Parse tags.
@@ -131,6 +142,7 @@
# Apply each tag.
for name, value in parsed_tags.items():
self.apply_item_tag( trans, user, item, name, value )
+
def get_tags_str( self, tags ):
"""Build a string from an item's tags."""
# Return empty string if there are no tags.
@@ -144,14 +156,17 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
return ", ".join( tags_str_list )
+
def get_tag_by_id( self, trans, tag_id ):
"""Get a Tag object from a tag id."""
return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first()
+
def get_tag_by_name( self, trans, tag_name ):
"""Get a Tag object from a tag name (string)."""
if tag_name:
return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first()
return None
+
def _create_tag( self, trans, tag_str ):
"""Create a Tag object from a tag string."""
tag_hierarchy = tag_str.split( self.hierarchy_separator )
@@ -169,6 +184,7 @@
parent_tag = tag
tag_prefix = tag.name + self.hierarchy_separator
return tag
+
def _get_or_create_tag( self, trans, tag_str ):
"""Get or create a Tag object from a tag string."""
# Scrub tag; if tag is None after being scrubbed, return None.
@@ -181,6 +197,7 @@
if tag is None:
tag = self._create_tag( trans, scrubbed_tag_str )
return tag
+
def _get_item_tag_assoc( self, user, item, tag_name ):
"""
Return ItemTagAssociation object for a user, item, and tag string; returns None if there is
@@ -191,6 +208,7 @@
if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ):
return item_tag_assoc
return None
+
def parse_tags( self, tag_str ):
"""
Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well.
@@ -210,6 +228,7 @@
scrubbed_value = self._scrub_tag_value( nv_pair[1] )
name_value_pairs[scrubbed_name] = scrubbed_value
return name_value_pairs
+
def _scrub_tag_value( self, value ):
"""Scrub a tag value."""
# Gracefully handle None:
@@ -219,6 +238,7 @@
reg_exp = re.compile( '\s' )
scrubbed_value = re.sub( reg_exp, "", value )
return scrubbed_value
+
def _scrub_tag_name( self, name ):
"""Scrub a tag name."""
# Gracefully handle None:
@@ -234,12 +254,14 @@
if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len:
return None
return scrubbed_name
+
def _scrub_tag_name_list( self, tag_name_list ):
"""Scrub a tag name list."""
scrubbed_tag_list = list()
for tag in tag_name_list:
scrubbed_tag_list.append( self._scrub_tag_name( tag ) )
return scrubbed_tag_list
+
def _get_name_value_pair( self, tag_str ):
"""Get name, value pair from a tag string."""
# Use regular expression to parse name, value.
@@ -250,6 +272,7 @@
name_value_pair.append( None )
return name_value_pair
+
class GalaxyTagHandler( TagHandler ):
def __init__( self ):
from galaxy import model
@@ -271,6 +294,7 @@
model.VisualizationTagAssociation,
model.VisualizationTagAssociation.table.c.visualization_id )
+
class CommunityTagHandler( TagHandler ):
def __init__( self ):
from galaxy.webapps.tool_shed import model
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/util/json.py
--- a/lib/galaxy/util/json.py
+++ b/lib/galaxy/util/json.py
@@ -57,7 +57,7 @@
return val
-def safe_dumps(*args, **kwargs):
+def safe_dumps( *args, **kwargs ):
"""
This is a wrapper around dumps that encodes Infinity and NaN values. It's a
fairly rare case (which will be low in request volume). Basically, we tell
@@ -65,10 +65,12 @@
re-encoding.
"""
try:
- dumped = json.dumps(*args, allow_nan=False, **kwargs)
+ dumped = json.dumps( *args, allow_nan=False, **kwargs )
except ValueError:
- obj = swap_inf_nan(copy.deepcopy(args[0]))
- dumped = json.dumps(obj, allow_nan=False, **kwargs)
+ obj = swap_inf_nan( copy.deepcopy( args[0] ) )
+ dumped = json.dumps( obj, allow_nan=False, **kwargs )
+ if kwargs.get( 'escape_closing_tags', True ):
+ return dumped.replace( '</', '<\\/' )
return dumped
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/util/validation.py
--- a/lib/galaxy/util/validation.py
+++ b/lib/galaxy/util/validation.py
@@ -8,8 +8,8 @@
def validate_and_sanitize_basestring( key, val ):
if not isinstance( val, basestring ):
- raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
- % ( key, str( type( val ) ) ) )
+ raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
+ % ( key, str( type( val ) ) ) )
return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' )
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/web/framework/helpers/__init__.py
--- a/lib/galaxy/web/framework/helpers/__init__.py
+++ b/lib/galaxy/web/framework/helpers/__init__.py
@@ -111,4 +111,3 @@
Returns true if input is a boolean and true or is a string and looks like a true value.
"""
return val == True or val in [ 'True', 'true', 'T', 't' ]
-
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/webapps/galaxy/controllers/tag.py
--- a/lib/galaxy/webapps/galaxy/controllers/tag.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tag.py
@@ -64,7 +64,7 @@
trans.log_action( user, unicode( "untag" ), context, params )
# Retag an item. All previous tags are deleted and new tags are applied.
- #(a)web.expose
+ @web.expose
@web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ):
"""
@@ -73,7 +73,7 @@
# Apply tags.
item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
user = trans.user
- self.get_tag_handler( trans ).delete_item_tags( trans, item )
+ self.get_tag_handler( trans ).delete_item_tags( trans, user, item )
self.get_tag_handler( trans ).apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) )
trans.sa_session.flush()
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/mvc/annotations.js
--- a/static/scripts/mvc/annotations.js
+++ b/static/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/mvc/tags.js
--- a/static/scripts/mvc/tags.js
+++ b/static/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/packed/mvc/annotations.js
--- a/static/scripts/packed/mvc/annotations.js
+++ b/static/scripts/packed/mvc/annotations.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',d,"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',_.escape(d),"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/packed/mvc/tags.js
--- a/static/scripts/packed/mvc/tags.js
+++ b/static/scripts/packed/mvc/tags.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.map(function(e){return _.escape(e)}).sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/galaxy_client_app.mako
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -15,7 +15,7 @@
//TODO: global...
%for key in kwargs:
( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = (
- ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} );
+ ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ) } );
%endfor
define( 'bootstrapped-data', function(){
return window.bootstrapped;
@@ -76,11 +76,17 @@
user_dict = trans.user.to_dict( view='element',
value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } )
user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
+ user_dict[ 'is_admin' ] = trans.user_is_admin()
# tags used
users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
+ tags_used = []
+ for tag in users_api_controller.get_user_tags_used( trans, user=trans.user ):
+ tag = tag | h
+ if tag:
+ tags_used.append( tag )
+ user_dict[ 'tags_used' ] = tags_used
+
return user_dict
usage = 0
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/tagging_common.mako
--- a/templates/tagging_common.mako
+++ b/templates/tagging_common.mako
@@ -19,7 +19,7 @@
## Render HTML for a list of tags.
<%def name="render_tagging_element_html(elt_id=None, tags=None, editable=True, use_toggle_link=True, input_size='15', in_form=False, tag_type='individual', render_add_tag_button=True)">
## Useful attributes.
- <%
+ <%
num_tags = len( tags )
%><div class="tag-element"
@@ -50,6 +50,7 @@
elif isinstance( tag, ItemTagAssociation ):
tag_name = tag.user_tname
tag_value = tag.user_value
+
## Convert tag name, value to unicode.
if isinstance( tag_name, str ):
tag_name = unicode( escape( tag_name ), 'utf-8' )
@@ -61,7 +62,7 @@
tag_str = tag_name
%><span class="tag-button">
- <span class="tag-name">${tag_str}</span>
+ <span class="tag-name">${tag_str | h}</span>
%if editable:
<img class="delete-tag-img" src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/>
%endif
@@ -186,10 +187,11 @@
## Build dict of tag name, values.
tag_names_and_values = dict()
for tag in item_tags:
- tag_name = tag.user_tname
+ tag_name = escape( tag.user_tname )
tag_value = ""
if tag.value is not None:
- tag_value = tag.user_value
+ tag_value = escape( tag.user_value )
+
## Tag names and values may be string or unicode object.
if isinstance( tag_name, str ):
tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8')
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/copy_view.mako
--- a/templates/webapps/galaxy/dataset/copy_view.mako
+++ b/templates/webapps/galaxy/dataset/copy_view.mako
@@ -53,7 +53,7 @@
%><option value="${trans.security.encode_id(hist.id)}" ${selected}>
- ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30)}${current_history_text}
+ ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30) | h}${current_history_text}
</option>
%endfor
</select>
@@ -70,7 +70,7 @@
%><div class="form-row"><input type="checkbox" name="source_content_ids" id="${input_id}" value="${input_id}"${checked}/>
- <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name)}</label>
+ <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name) | h}</label></div>
%endfor
%else:
@@ -95,7 +95,7 @@
if encoded_id == target_history_id:
selected = " selected='selected'"
%>
- <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30)}${source_history_text}</option>
+ <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30) | h}${source_history_text}</option>
%endfor
</select><br /><br /><a style="margin-left: 10px;" href="javascript:void(0);" id="select-multiple">Choose multiple histories</a>
@@ -110,7 +110,7 @@
%><div class="form-row"><input type="checkbox" name="target_history_ids" id="hist_${encoded_id}" value="${encoded_id}"/>
- <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) }${cur_history_text}</label>
+ <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) | h }${cur_history_text}</label></div>
%endfor
</div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/display.mako
--- a/templates/webapps/galaxy/dataset/display.mako
+++ b/templates/webapps/galaxy/dataset/display.mako
@@ -26,13 +26,11 @@
data.createTabularDatasetChunkedView({
// TODO: encode id.
dataset_config:
- _.extend( ${h.dumps( item.to_dict() )},
- {
- chunk_url: "${h.url_for( controller='/dataset', action='display',
- dataset_id=trans.security.encode_id( item.id ))}",
- first_data_chunk: ${first_chunk}
- }
- ),
+ _.extend( ${h.dumps( item.to_dict() )}, {
+ chunk_url: "${h.url_for( controller='/dataset', action='display',
+ dataset_id=trans.security.encode_id( item.id ))}",
+ first_data_chunk: ${first_chunk}
+ }),
parent_elt: $('.page-body')
});
});
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/embed.mako
--- a/templates/webapps/galaxy/dataset/embed.mako
+++ b/templates/webapps/galaxy/dataset/embed.mako
@@ -4,10 +4,13 @@
%><%def name="render_item_links( dataset )">
- <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}" title="Save dataset" class="icon-button disk"></a>
+ <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}"
+ title="Save dataset" class="icon-button disk"></a>
## Links for importing and viewing an item.
- <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}" title="Import dataset" class="icon-button import"></a>
- <a class="icon-button go-to-full-screen" href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}" title="Go to dataset"></a>
+ <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}"
+ title="Import dataset" class="icon-button import"></a>
+ <a href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}"
+ title="Go to dataset" class="icon-button go-to-full-screen"></a></%def>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -49,7 +49,7 @@
<body><h2>Dataset generation errors</h2>
- <p><b>Dataset ${hda.hid}: ${hda.display_name()}</b></p>
+ <p><b>Dataset ${hda.hid}: ${hda.display_name() | h}</b></p><% job = hda.creating_job %>
%if job:
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/security_common.mako
--- a/templates/webapps/galaxy/dataset/security_common.mako
+++ b/templates/webapps/galaxy/dataset/security_common.mako
@@ -77,7 +77,7 @@
else:
current_actions = []
permitted_actions = {}.items()
- obj_str = 'unknown object %s' %obj_name
+ obj_str = 'unknown object %s' % obj_name
obj_type = ''
%><script type="text/javascript">
@@ -104,7 +104,7 @@
});
</script><div class="toolForm">
- <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str}</div>
+ <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str | h}</div><div class="toolFormBody"><form name="edit_role_associations" id="edit_role_associations" action="${form_url}" method="post"><div class="form-row"></div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/tabular_chunked.mako
--- a/templates/webapps/galaxy/dataset/tabular_chunked.mako
+++ b/templates/webapps/galaxy/dataset/tabular_chunked.mako
@@ -15,14 +15,12 @@
}
});
- require(['mvc/data'], function(data) {
+ require([ 'mvc/data' ], function( data ) {
data.createTabularDatasetChunkedView({
- dataset_config: _.extend( ${h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )},
- {
- first_data_chunk: ${chunk}
- }
- ),
- parent_elt: $('body')
+ dataset_config : _.extend( ${ h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )}, {
+ first_data_chunk: ${ chunk }
+ }),
+ parent_elt : $( 'body' )
});
});
</script>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -1,32 +1,4 @@
-## get user data
-<%def name="get_user_json()">
-<%
- """Bootstrapping user API JSON"""
- #TODO: move into common location (poss. BaseController)
- if trans.user:
- user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id,
- 'total_disk_usage': float } )
- user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
- users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
- else:
- usage = 0
- percent = None
- try:
- usage = trans.app.quota_agent.get_usage( trans, history=trans.history )
- percent = trans.app.quota_agent.get_percent( trans=trans, usage=usage )
- except AssertionError, assertion:
- # no history for quota_agent.get_usage assertion
- pass
- user_dict = {
- 'total_disk_usage' : int( usage ),
- 'nice_total_disk_usage' : util.nice_size( usage ),
- 'quota_percent' : percent
- }
- return user_dict
-%>
-</%def>
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## masthead head generator
<%def name="load(active_view = None)">
@@ -87,7 +59,7 @@
], function( mod_masthead, mod_menu, mod_modal, mod_frame, GalaxyUpload, user, quotameter ){
if( !Galaxy.currUser ){
// this doesn't need to wait for the page being readied
- Galaxy.currUser = new user.User(${ h.dumps( get_user_json(), indent=2 ) });
+ Galaxy.currUser = new user.User(${ h.dumps( masthead_config[ 'user' ][ 'json' ], indent=2 ) });
}
$(function() {
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/embed.mako
--- a/templates/webapps/galaxy/history/embed.mako
+++ b/templates/webapps/galaxy/history/embed.mako
@@ -24,7 +24,7 @@
</a></h4>
%if hasattr( item, "annotation") and item.annotation:
- <div class="annotation">${item.annotation}</div>
+ <div class="annotation">${item.annotation | h}</div>
%endif
</div><div class='summary-content'>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/history_panel.mako
--- a/templates/webapps/galaxy/history/history_panel.mako
+++ /dev/null
@@ -1,14 +0,0 @@
-## shortcuts for script tags that create history panels
-## ----------------------------------------------------------------------------
-<%def name="current_history_panel( selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="history_panel( history_id, selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="bootstrapped_history_panel( history, hdas, selector_to_attach_to=None, options )">
-</%def>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/share.mako
--- a/templates/webapps/galaxy/history/share.mako
+++ b/templates/webapps/galaxy/history/share.mako
@@ -20,7 +20,7 @@
<tr><td><input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
- ${ util.unicodify( history.name )}
+ ${ util.unicodify( history.name ) | h }
</td><td>
%if len( history.datasets ) < 1:
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -1,4 +1,4 @@
-<%namespace file="/galaxy.masthead.mako" import="get_user_json" />
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## ----------------------------------------------------------------------------
<%!
@@ -166,9 +166,9 @@
// use_panels effects where the the center_panel() is rendered:
// w/o it renders to the body, w/ it renders to #center - we need to adjust a few things for scrolling to work
var hasMasthead = ${ 'true' if use_panels else 'false' },
- userIsOwner = ${'true' if user_is_owner else 'false'},
- historyJSON = ${h.dumps( history )},
- hdaJSON = ${h.dumps( hdas )},
+ userIsOwner = ${ 'true' if user_is_owner else 'false' },
+ historyJSON = ${ h.dumps( history ) },
+ hdaJSON = ${ h.dumps( hdas ) },
panelToUse = ( userIsOwner )?
//TODO: change class names
({ location: 'mvc/history/history-panel-edit', className: 'HistoryPanelEdit' }):
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/page/editor.mako
--- a/templates/webapps/galaxy/page/editor.mako
+++ b/templates/webapps/galaxy/page/editor.mako
@@ -47,7 +47,7 @@
<a id="close-button" class="panel-header-button">Close</a></div><div class="unified-panel-header-inner">
- Page Editor <span style="font-weight: normal">| Title : ${page.title}</span>
+ Page Editor <span style="font-weight: normal">| Title : ${page.title | h}</span></div></div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/page/index.mako
--- a/templates/webapps/galaxy/page/index.mako
+++ b/templates/webapps/galaxy/page/index.mako
@@ -30,7 +30,7 @@
<% page = association.page %><tr><td>
- <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title}</a>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title | h}</a></td><td>${page.user.username}</td><td>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Merged in carlfeberhard/carlfeberhard-galaxy-central-stable/stable (pull request #594)
by commits-noreply@bitbucket.org 08 Dec '14
by commits-noreply@bitbucket.org 08 Dec '14
08 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0c8ac7330cdd/
Changeset: 0c8ac7330cdd
Branch: stable
User: dannon
Date: 2014-12-08 16:44:52+00:00
Summary: Merged in carlfeberhard/carlfeberhard-galaxy-central-stable/stable (pull request #594)
[STABLE] Next-stable security fixes to stable.
Affected #: 26 files
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 client/galaxy/scripts/mvc/annotations.js
--- a/client/galaxy/scripts/mvc/annotations.js
+++ b/client/galaxy/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 client/galaxy/scripts/mvc/tags.js
--- a/client/galaxy/scripts/mvc/tags.js
+++ b/client/galaxy/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/tags/tag_handler.py
--- a/lib/galaxy/tags/tag_handler.py
+++ b/lib/galaxy/tags/tag_handler.py
@@ -1,5 +1,7 @@
-import re, logging
-from sqlalchemy.sql.expression import func, and_
+import re
+import logging
+from sqlalchemy.sql.expression import func
+from sqlalchemy.sql.expression import and_
from sqlalchemy.sql import select
log = logging.getLogger( __name__ )
@@ -25,12 +27,15 @@
self.key_value_separators = "=:"
# Initialize with known classes - add to this in subclasses.
self.item_tag_assoc_info = {}
+
def get_tag_assoc_class( self, item_class ):
"""Returns tag association class for item class."""
return self.item_tag_assoc_info[item_class.__name__].tag_assoc_class
+
def get_id_col_in_item_tag_assoc_table( self, item_class ):
"""Returns item id column in class' item-tag association table."""
return self.item_tag_assoc_info[item_class.__name__].item_id_col
+
def get_community_tags( self, trans, item=None, limit=None ):
"""Returns community tags for an item."""
# Get item-tag association class.
@@ -58,6 +63,7 @@
tag_id = row[0]
community_tags.append( self.get_tag_by_id( trans, tag_id ) )
return community_tags
+
def get_tool_tags( self, trans ):
result_set = trans.sa_session.execute( select( columns=[ trans.app.model.ToolTagAssociation.table.c.tag_id ],
from_obj=trans.app.model.ToolTagAssociation.table ).distinct() )
@@ -67,6 +73,7 @@
tag_id = row[0]
tags.append( self.get_tag_by_id( trans, tag_id ) )
return tags
+
def remove_item_tag( self, trans, user, item, tag_name ):
"""Remove a tag from an item."""
# Get item tag association.
@@ -78,6 +85,7 @@
item.tags.remove( item_tag_assoc )
return True
return False
+
def delete_item_tags( self, trans, user, item ):
"""Delete tags from an item."""
# Delete item-tag associations.
@@ -85,6 +93,7 @@
trans.sa_session.delete( tag )
# Delete tags from item.
del item.tags[:]
+
def item_has_tag( self, trans, user, item, tag ):
"""Returns true if item is has a given tag."""
# Get tag name.
@@ -97,6 +106,7 @@
if item_tag_assoc:
return True
return False
+
def apply_item_tag( self, trans, user, item, name, value=None ):
# Use lowercase name for searching/creating tag.
lc_name = name.lower()
@@ -124,6 +134,7 @@
item_tag_assoc.user_value = value
item_tag_assoc.value = lc_value
return item_tag_assoc
+
def apply_item_tags( self, trans, user, item, tags_str ):
"""Apply tags to an item."""
# Parse tags.
@@ -131,6 +142,7 @@
# Apply each tag.
for name, value in parsed_tags.items():
self.apply_item_tag( trans, user, item, name, value )
+
def get_tags_str( self, tags ):
"""Build a string from an item's tags."""
# Return empty string if there are no tags.
@@ -144,14 +156,17 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
return ", ".join( tags_str_list )
+
def get_tag_by_id( self, trans, tag_id ):
"""Get a Tag object from a tag id."""
return trans.sa_session.query( trans.app.model.Tag ).filter_by( id=tag_id ).first()
+
def get_tag_by_name( self, trans, tag_name ):
"""Get a Tag object from a tag name (string)."""
if tag_name:
return trans.sa_session.query( trans.app.model.Tag ).filter_by( name=tag_name.lower() ).first()
return None
+
def _create_tag( self, trans, tag_str ):
"""Create a Tag object from a tag string."""
tag_hierarchy = tag_str.split( self.hierarchy_separator )
@@ -169,6 +184,7 @@
parent_tag = tag
tag_prefix = tag.name + self.hierarchy_separator
return tag
+
def _get_or_create_tag( self, trans, tag_str ):
"""Get or create a Tag object from a tag string."""
# Scrub tag; if tag is None after being scrubbed, return None.
@@ -181,6 +197,7 @@
if tag is None:
tag = self._create_tag( trans, scrubbed_tag_str )
return tag
+
def _get_item_tag_assoc( self, user, item, tag_name ):
"""
Return ItemTagAssociation object for a user, item, and tag string; returns None if there is
@@ -191,6 +208,7 @@
if ( item_tag_assoc.user == user ) and ( item_tag_assoc.user_tname == scrubbed_tag_name ):
return item_tag_assoc
return None
+
def parse_tags( self, tag_str ):
"""
Returns a list of raw (tag-name, value) pairs derived from a string; method scrubs tag names and values as well.
@@ -210,6 +228,7 @@
scrubbed_value = self._scrub_tag_value( nv_pair[1] )
name_value_pairs[scrubbed_name] = scrubbed_value
return name_value_pairs
+
def _scrub_tag_value( self, value ):
"""Scrub a tag value."""
# Gracefully handle None:
@@ -219,6 +238,7 @@
reg_exp = re.compile( '\s' )
scrubbed_value = re.sub( reg_exp, "", value )
return scrubbed_value
+
def _scrub_tag_name( self, name ):
"""Scrub a tag name."""
# Gracefully handle None:
@@ -234,12 +254,14 @@
if len( scrubbed_name ) < self.min_tag_len or len( scrubbed_name ) > self.max_tag_len:
return None
return scrubbed_name
+
def _scrub_tag_name_list( self, tag_name_list ):
"""Scrub a tag name list."""
scrubbed_tag_list = list()
for tag in tag_name_list:
scrubbed_tag_list.append( self._scrub_tag_name( tag ) )
return scrubbed_tag_list
+
def _get_name_value_pair( self, tag_str ):
"""Get name, value pair from a tag string."""
# Use regular expression to parse name, value.
@@ -250,6 +272,7 @@
name_value_pair.append( None )
return name_value_pair
+
class GalaxyTagHandler( TagHandler ):
def __init__( self ):
from galaxy import model
@@ -271,6 +294,7 @@
model.VisualizationTagAssociation,
model.VisualizationTagAssociation.table.c.visualization_id )
+
class CommunityTagHandler( TagHandler ):
def __init__( self ):
from galaxy.webapps.tool_shed import model
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/util/json.py
--- a/lib/galaxy/util/json.py
+++ b/lib/galaxy/util/json.py
@@ -57,7 +57,7 @@
return val
-def safe_dumps(*args, **kwargs):
+def safe_dumps( *args, **kwargs ):
"""
This is a wrapper around dumps that encodes Infinity and NaN values. It's a
fairly rare case (which will be low in request volume). Basically, we tell
@@ -65,10 +65,12 @@
re-encoding.
"""
try:
- dumped = json.dumps(*args, allow_nan=False, **kwargs)
+ dumped = json.dumps( *args, allow_nan=False, **kwargs )
except ValueError:
- obj = swap_inf_nan(copy.deepcopy(args[0]))
- dumped = json.dumps(obj, allow_nan=False, **kwargs)
+ obj = swap_inf_nan( copy.deepcopy( args[0] ) )
+ dumped = json.dumps( obj, allow_nan=False, **kwargs )
+ if kwargs.get( 'escape_closing_tags', True ):
+ return dumped.replace( '</', '<\\/' )
return dumped
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/util/validation.py
--- a/lib/galaxy/util/validation.py
+++ b/lib/galaxy/util/validation.py
@@ -8,8 +8,8 @@
def validate_and_sanitize_basestring( key, val ):
if not isinstance( val, basestring ):
- raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
- % ( key, str( type( val ) ) ) )
+ raise exceptions.RequestParameterInvalidException( '%s must be a string or unicode: %s'
+ % ( key, str( type( val ) ) ) )
return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' )
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/web/framework/helpers/__init__.py
--- a/lib/galaxy/web/framework/helpers/__init__.py
+++ b/lib/galaxy/web/framework/helpers/__init__.py
@@ -111,4 +111,3 @@
Returns true if input is a boolean and true or is a string and looks like a true value.
"""
return val == True or val in [ 'True', 'true', 'T', 't' ]
-
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 lib/galaxy/webapps/galaxy/controllers/tag.py
--- a/lib/galaxy/webapps/galaxy/controllers/tag.py
+++ b/lib/galaxy/webapps/galaxy/controllers/tag.py
@@ -64,7 +64,7 @@
trans.log_action( user, unicode( "untag" ), context, params )
# Retag an item. All previous tags are deleted and new tags are applied.
- #(a)web.expose
+ @web.expose
@web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
def retag_async( self, trans, item_id=None, item_class=None, new_tags=None ):
"""
@@ -73,7 +73,7 @@
# Apply tags.
item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
user = trans.user
- self.get_tag_handler( trans ).delete_item_tags( trans, item )
+ self.get_tag_handler( trans ).delete_item_tags( trans, user, item )
self.get_tag_handler( trans ).apply_item_tags( trans, user, item, new_tags.encode( 'utf-8' ) )
trans.sa_session.flush()
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/mvc/annotations.js
--- a/static/scripts/mvc/annotations.js
+++ b/static/scripts/mvc/annotations.js
@@ -56,7 +56,7 @@
'<label class="prompt">', _l( 'Annotation' ), '</label>',
// set up initial tags by adding as CSV to input vals (necc. to init select2)
'<div class="annotation" title="', _l( 'Edit annotation' ), '">',
- annotation,
+ _.escape( annotation ),
'</div>'
].join( '' );
},
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/mvc/tags.js
--- a/static/scripts/mvc/tags.js
+++ b/static/scripts/mvc/tags.js
@@ -56,7 +56,9 @@
if( !_.isArray( tagsArray ) || _.isEmpty( tagsArray ) ){
return '';
}
- return tagsArray.sort().join( ',' );
+ return tagsArray.map( function( tag ){
+ return _.escape( tag );
+ }).sort().join( ',' );
},
/** @returns {jQuery} the input for this view */
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/packed/mvc/annotations.js
--- a/static/scripts/packed/mvc/annotations.js
+++ b/static/scripts/packed/mvc/annotations.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',d,"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,c){var b=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"annotation-display",initialize:function(d){d=d||{};this.tooltipConfig=d.tooltipConfig||{placement:"bottom"};this.listenTo(this.model,"change:annotation",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$el.find("[title]").tooltip(this.tooltipConfig);this.$annotation().make_text_editable({use_textarea:true,on_finish:function(e){d.$annotation().text(e);d.model.save({annotation:e},{silent:true}).fail(function(){d.$annotation().text(d.model.previous("annotation"))})}});return this},_template:function(){var d=this.model.get("annotation");return['<label class="prompt">',c("Annotation"),"</label>",'<div class="annotation" title="',c("Edit annotation"),'">',_.escape(d),"</div>"].join("")},$annotation:function(){return this.$el.find(".annotation")},remove:function(){this.$annotation.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["AnnotationEditor(",this.model+"",")"].join("")}});return{AnnotationEditor:b}});
\ No newline at end of file
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 static/scripts/packed/mvc/tags.js
--- a/static/scripts/packed/mvc/tags.js
+++ b/static/scripts/packed/mvc/tags.js
@@ -1,1 +1,1 @@
-define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
+define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend(a.HiddenUntilActivatedViewMixin).extend({tagName:"div",className:"tags-display",initialize:function(d){this.listenTo(this.model,"change:tags",function(){this.render()});this.hiddenUntilActivated(d.$activator,d)},render:function(){var d=this;this.$el.html(this._template());this.$input().select2({placeholder:"Add tags",width:"100%",tags:function(){return d._getTagsUsed()}});this._setUpBehaviors();return this},_template:function(){return['<label class="prompt">',b("Tags"),"</label>",'<input class="tags-input" value="',this.tagsToCSV(),'" />'].join("")},tagsToCSV:function(){var d=this.model.get("tags");if(!_.isArray(d)||_.isEmpty(d)){return""}return d.map(function(e){return _.escape(e)}).sort().join(",")},$input:function(){return this.$el.find("input.tags-input")},_getTagsUsed:function(){return Galaxy.currUser.get("tags_used")},_setUpBehaviors:function(){var d=this;this.$input().on("change",function(e){d.model.save({tags:e.val},{silent:true});if(e.added){d._addNewTagToTagsUsed(e.added.text+"")}})},_addNewTagToTagsUsed:function(d){var e=Galaxy.currUser.get("tags_used");if(!_.contains(e,d)){e.push(d);e.sort();Galaxy.currUser.set("tags_used",e)}},remove:function(){this.$input.off();this.stopListening(this.model);Backbone.View.prototype.remove.call(this)},toString:function(){return["TagsEditor(",this.model+"",")"].join("")}});return{TagsEditor:c}});
\ No newline at end of file
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/galaxy_client_app.mako
--- a/templates/galaxy_client_app.mako
+++ b/templates/galaxy_client_app.mako
@@ -15,7 +15,7 @@
//TODO: global...
%for key in kwargs:
( window.bootstrapped = window.bootstrapped || {} )[ '${key}' ] = (
- ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) )} );
+ ${ h.dumps( kwargs[ key ], indent=( 2 if trans.debug else 0 ) ) } );
%endfor
define( 'bootstrapped-data', function(){
return window.bootstrapped;
@@ -76,11 +76,17 @@
user_dict = trans.user.to_dict( view='element',
value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } )
user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
+ user_dict[ 'is_admin' ] = trans.user_is_admin()
# tags used
users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
+ tags_used = []
+ for tag in users_api_controller.get_user_tags_used( trans, user=trans.user ):
+ tag = tag | h
+ if tag:
+ tags_used.append( tag )
+ user_dict[ 'tags_used' ] = tags_used
+
return user_dict
usage = 0
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/tagging_common.mako
--- a/templates/tagging_common.mako
+++ b/templates/tagging_common.mako
@@ -19,7 +19,7 @@
## Render HTML for a list of tags.
<%def name="render_tagging_element_html(elt_id=None, tags=None, editable=True, use_toggle_link=True, input_size='15', in_form=False, tag_type='individual', render_add_tag_button=True)">
## Useful attributes.
- <%
+ <%
num_tags = len( tags )
%><div class="tag-element"
@@ -50,6 +50,7 @@
elif isinstance( tag, ItemTagAssociation ):
tag_name = tag.user_tname
tag_value = tag.user_value
+
## Convert tag name, value to unicode.
if isinstance( tag_name, str ):
tag_name = unicode( escape( tag_name ), 'utf-8' )
@@ -61,7 +62,7 @@
tag_str = tag_name
%><span class="tag-button">
- <span class="tag-name">${tag_str}</span>
+ <span class="tag-name">${tag_str | h}</span>
%if editable:
<img class="delete-tag-img" src="${h.url_for('/static/images/delete_tag_icon_gray.png')}"/>
%endif
@@ -186,10 +187,11 @@
## Build dict of tag name, values.
tag_names_and_values = dict()
for tag in item_tags:
- tag_name = tag.user_tname
+ tag_name = escape( tag.user_tname )
tag_value = ""
if tag.value is not None:
- tag_value = tag.user_value
+ tag_value = escape( tag.user_value )
+
## Tag names and values may be string or unicode object.
if isinstance( tag_name, str ):
tag_names_and_values[unicode(tag_name, 'utf-8')] = unicode(tag_value, 'utf-8')
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/copy_view.mako
--- a/templates/webapps/galaxy/dataset/copy_view.mako
+++ b/templates/webapps/galaxy/dataset/copy_view.mako
@@ -53,7 +53,7 @@
%><option value="${trans.security.encode_id(hist.id)}" ${selected}>
- ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30)}${current_history_text}
+ ${i + 1}: ${h.truncate(util.unicodify( hist.name ), 30) | h}${current_history_text}
</option>
%endfor
</select>
@@ -70,7 +70,7 @@
%><div class="form-row"><input type="checkbox" name="source_content_ids" id="${input_id}" value="${input_id}"${checked}/>
- <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name)}</label>
+ <label for="${input_id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${h.to_unicode(data.name) | h}</label></div>
%endfor
%else:
@@ -95,7 +95,7 @@
if encoded_id == target_history_id:
selected = " selected='selected'"
%>
- <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30)}${source_history_text}</option>
+ <option value="${encoded_id}"${selected}>${i + 1}: ${h.truncate( util.unicodify( hist.name ), 30) | h}${source_history_text}</option>
%endfor
</select><br /><br /><a style="margin-left: 10px;" href="javascript:void(0);" id="select-multiple">Choose multiple histories</a>
@@ -110,7 +110,7 @@
%><div class="form-row"><input type="checkbox" name="target_history_ids" id="hist_${encoded_id}" value="${encoded_id}"/>
- <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) }${cur_history_text}</label>
+ <label for="hist_${encoded_id}" style="display: inline; font-weight:normal;">${i + 1}: ${ util.unicodify( hist.name ) | h }${cur_history_text}</label></div>
%endfor
</div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/display.mako
--- a/templates/webapps/galaxy/dataset/display.mako
+++ b/templates/webapps/galaxy/dataset/display.mako
@@ -26,13 +26,11 @@
data.createTabularDatasetChunkedView({
// TODO: encode id.
dataset_config:
- _.extend( ${h.dumps( item.to_dict() )},
- {
- chunk_url: "${h.url_for( controller='/dataset', action='display',
- dataset_id=trans.security.encode_id( item.id ))}",
- first_data_chunk: ${first_chunk}
- }
- ),
+ _.extend( ${h.dumps( item.to_dict() )}, {
+ chunk_url: "${h.url_for( controller='/dataset', action='display',
+ dataset_id=trans.security.encode_id( item.id ))}",
+ first_data_chunk: ${first_chunk}
+ }),
parent_elt: $('.page-body')
});
});
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/embed.mako
--- a/templates/webapps/galaxy/dataset/embed.mako
+++ b/templates/webapps/galaxy/dataset/embed.mako
@@ -4,10 +4,13 @@
%><%def name="render_item_links( dataset )">
- <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}" title="Save dataset" class="icon-button disk"></a>
+ <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}"
+ title="Save dataset" class="icon-button disk"></a>
## Links for importing and viewing an item.
- <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}" title="Import dataset" class="icon-button import"></a>
- <a class="icon-button go-to-full-screen" href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}" title="Go to dataset"></a>
+ <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}"
+ title="Import dataset" class="icon-button import"></a>
+ <a href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}"
+ title="Go to dataset" class="icon-button go-to-full-screen"></a></%def>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/errors.mako
--- a/templates/webapps/galaxy/dataset/errors.mako
+++ b/templates/webapps/galaxy/dataset/errors.mako
@@ -49,7 +49,7 @@
<body><h2>Dataset generation errors</h2>
- <p><b>Dataset ${hda.hid}: ${hda.display_name()}</b></p>
+ <p><b>Dataset ${hda.hid}: ${hda.display_name() | h}</b></p><% job = hda.creating_job %>
%if job:
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/security_common.mako
--- a/templates/webapps/galaxy/dataset/security_common.mako
+++ b/templates/webapps/galaxy/dataset/security_common.mako
@@ -77,7 +77,7 @@
else:
current_actions = []
permitted_actions = {}.items()
- obj_str = 'unknown object %s' %obj_name
+ obj_str = 'unknown object %s' % obj_name
obj_type = ''
%><script type="text/javascript">
@@ -104,7 +104,7 @@
});
</script><div class="toolForm">
- <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str}</div>
+ <div class="toolFormTitle">Manage ${obj_type} permissions on ${obj_str | h}</div><div class="toolFormBody"><form name="edit_role_associations" id="edit_role_associations" action="${form_url}" method="post"><div class="form-row"></div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/dataset/tabular_chunked.mako
--- a/templates/webapps/galaxy/dataset/tabular_chunked.mako
+++ b/templates/webapps/galaxy/dataset/tabular_chunked.mako
@@ -15,14 +15,12 @@
}
});
- require(['mvc/data'], function(data) {
+ require([ 'mvc/data' ], function( data ) {
data.createTabularDatasetChunkedView({
- dataset_config: _.extend( ${h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )},
- {
- first_data_chunk: ${chunk}
- }
- ),
- parent_elt: $('body')
+ dataset_config : _.extend( ${ h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )}, {
+ first_data_chunk: ${ chunk }
+ }),
+ parent_elt : $( 'body' )
});
});
</script>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -1,32 +1,4 @@
-## get user data
-<%def name="get_user_json()">
-<%
- """Bootstrapping user API JSON"""
- #TODO: move into common location (poss. BaseController)
- if trans.user:
- user_dict = trans.user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id,
- 'total_disk_usage': float } )
- user_dict[ 'quota_percent' ] = trans.app.quota_agent.get_percent( trans=trans )
- users_api_controller = trans.webapp.api_controllers[ 'users' ]
- user_dict[ 'tags_used' ] = users_api_controller.get_user_tags_used( trans, user=trans.user )
- user_dict[ 'is_admin' ] = trans.user_is_admin()
- else:
- usage = 0
- percent = None
- try:
- usage = trans.app.quota_agent.get_usage( trans, history=trans.history )
- percent = trans.app.quota_agent.get_percent( trans=trans, usage=usage )
- except AssertionError, assertion:
- # no history for quota_agent.get_usage assertion
- pass
- user_dict = {
- 'total_disk_usage' : int( usage ),
- 'nice_total_disk_usage' : util.nice_size( usage ),
- 'quota_percent' : percent
- }
- return user_dict
-%>
-</%def>
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## masthead head generator
<%def name="load(active_view = None)">
@@ -87,7 +59,7 @@
], function( mod_masthead, mod_menu, mod_modal, mod_frame, GalaxyUpload, user, quotameter ){
if( !Galaxy.currUser ){
// this doesn't need to wait for the page being readied
- Galaxy.currUser = new user.User(${ h.dumps( get_user_json(), indent=2 ) });
+ Galaxy.currUser = new user.User(${ h.dumps( masthead_config[ 'user' ][ 'json' ], indent=2 ) });
}
$(function() {
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/embed.mako
--- a/templates/webapps/galaxy/history/embed.mako
+++ b/templates/webapps/galaxy/history/embed.mako
@@ -24,7 +24,7 @@
</a></h4>
%if hasattr( item, "annotation") and item.annotation:
- <div class="annotation">${item.annotation}</div>
+ <div class="annotation">${item.annotation | h}</div>
%endif
</div><div class='summary-content'>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/history_panel.mako
--- a/templates/webapps/galaxy/history/history_panel.mako
+++ /dev/null
@@ -1,14 +0,0 @@
-## shortcuts for script tags that create history panels
-## ----------------------------------------------------------------------------
-<%def name="current_history_panel( selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="history_panel( history_id, selector_to_attach_to=None, options )">
-</%def>
-
-
-## ----------------------------------------------------------------------------
-<%def name="bootstrapped_history_panel( history, hdas, selector_to_attach_to=None, options )">
-</%def>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/share.mako
--- a/templates/webapps/galaxy/history/share.mako
+++ b/templates/webapps/galaxy/history/share.mako
@@ -20,7 +20,7 @@
<tr><td><input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
- ${ util.unicodify( history.name )}
+ ${ util.unicodify( history.name ) | h }
</td><td>
%if len( history.datasets ) < 1:
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -1,4 +1,4 @@
-<%namespace file="/galaxy.masthead.mako" import="get_user_json" />
+<%namespace file="/galaxy_client_app.mako" import="get_user_json" />
## ----------------------------------------------------------------------------
<%!
@@ -166,9 +166,9 @@
// use_panels effects where the the center_panel() is rendered:
// w/o it renders to the body, w/ it renders to #center - we need to adjust a few things for scrolling to work
var hasMasthead = ${ 'true' if use_panels else 'false' },
- userIsOwner = ${'true' if user_is_owner else 'false'},
- historyJSON = ${h.dumps( history )},
- hdaJSON = ${h.dumps( hdas )},
+ userIsOwner = ${ 'true' if user_is_owner else 'false' },
+ historyJSON = ${ h.dumps( history ) },
+ hdaJSON = ${ h.dumps( hdas ) },
panelToUse = ( userIsOwner )?
//TODO: change class names
({ location: 'mvc/history/history-panel-edit', className: 'HistoryPanelEdit' }):
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/page/editor.mako
--- a/templates/webapps/galaxy/page/editor.mako
+++ b/templates/webapps/galaxy/page/editor.mako
@@ -47,7 +47,7 @@
<a id="close-button" class="panel-header-button">Close</a></div><div class="unified-panel-header-inner">
- Page Editor <span style="font-weight: normal">| Title : ${page.title}</span>
+ Page Editor <span style="font-weight: normal">| Title : ${page.title | h}</span></div></div>
diff -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 -r 0c8ac7330cdd467e9c7ef6f02778dca07a577b79 templates/webapps/galaxy/page/index.mako
--- a/templates/webapps/galaxy/page/index.mako
+++ b/templates/webapps/galaxy/page/index.mako
@@ -30,7 +30,7 @@
<% page = association.page %><tr><td>
- <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title}</a>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for(controller='page', action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title | h}</a></td><td>${page.user.username}</td><td>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
24 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8b4a7e48d052/
Changeset: 8b4a7e48d052
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize workflow and input dataset names in workflow run.mako.
Affected #: 1 file
diff -r 885f940bff64bbb6769fd31b21b0c73f4bfe1642 -r 8b4a7e48d052ef1c2275061c44827ad8b20ec57f templates/webapps/galaxy/workflow/run.mako
--- a/templates/webapps/galaxy/workflow/run.mako
+++ b/templates/webapps/galaxy/workflow/run.mako
@@ -372,7 +372,7 @@
<% cls = "form-row" %>
%endif
<div class="${cls}">
- <label>${param.get_label()}</label>
+ <label>${param.get_label() | h}</label><div>
%if isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ):
%if ( prefix + param.name ) in step.input_connections_by_name:
@@ -474,7 +474,7 @@
<span class="action-button" id="hide_all_tool_body">Collapse</span></div>
-<h2>Running workflow "${h.to_unicode( workflow.name )}"</h2>
+<h2>Running workflow "${h.to_unicode( workflow.name ) | h}"</h2>
%if has_upgrade_messages:
<div class="warningmessage">
@@ -586,7 +586,7 @@
%else:
<div class="toolForm"><div class="toolFormTitle">
- <span class='title_ul_text'>Step ${int(step.order_index)+1}: ${module.name}</span>
+ <span class='title_ul_text'>Step ${int(step.order_index)+1}: ${module.name | h}</span>
% if step.annotations:
<div class="step-annotation">${step.annotations[0].annotation}</div>
% endif
https://bitbucket.org/galaxy/galaxy-central/commits/bf1b90f6b3ba/
Changeset: bf1b90f6b3ba
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize display of workflow parameters in workflow run.mako.
Affected #: 1 file
diff -r 8b4a7e48d052ef1c2275061c44827ad8b20ec57f -r bf1b90f6b3baa794955a1b7d2bb7b4c4dea52219 templates/webapps/galaxy/workflow/run.mako
--- a/templates/webapps/galaxy/workflow/run.mako
+++ b/templates/webapps/galaxy/workflow/run.mako
@@ -574,6 +574,7 @@
<%
pja_ss_all = []
for pja_ss in [ActionBox.get_short_str(pja) for pja in step.post_job_actions]:
+ pja_ss = h.escape( pja_ss )
for rematch in re.findall('\$\{.+?\}', pja_ss):
pja_ss = pja_ss.replace(rematch, '<span style="background-color:%s" class="wfpspan wf_parm__%s pja_wfp">%s</span>' % (wf_parms[rematch[2:-1]], rematch[2:-1], rematch[2:-1]))
pja_ss_all.append(pja_ss)
https://bitbucket.org/galaxy/galaxy-central/commits/a6708f36b062/
Changeset: a6708f36b062
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize workflow run.mako parameters not sanitized by tooling code.
Affected #: 1 file
diff -r bf1b90f6b3baa794955a1b7d2bb7b4c4dea52219 -r a6708f36b0624e60d266ba2a441aaf5a9143fd1d templates/webapps/galaxy/workflow/run.mako
--- a/templates/webapps/galaxy/workflow/run.mako
+++ b/templates/webapps/galaxy/workflow/run.mako
@@ -444,7 +444,7 @@
%else:
<span class="workflow_parameters"><span class="uneditable_field">
- ${param.value_to_display_text( value, app )}
+ ${param.value_to_display_text( value, app ) | h}
</span><span class="editable_field"><span class="editable">
https://bitbucket.org/galaxy/galaxy-central/commits/76da60bbe585/
Changeset: 76da60bbe585
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: More sanitization in workflow display.mako.
Affected #: 1 file
diff -r a6708f36b0624e60d266ba2a441aaf5a9143fd1d -r 76da60bbe585f19fc968ba2aa4a5e226c02cd92e templates/webapps/galaxy/workflow/display.mako
--- a/templates/webapps/galaxy/workflow/display.mako
+++ b/templates/webapps/galaxy/workflow/display.mako
@@ -40,7 +40,7 @@
<%def name="row_for_param( param, value, other_values, prefix, step )"><% cls = "form-row" %><div class="${cls}">
- <label>${param.get_label()}</label>
+ <label>${param.get_label() | h}</label><div>
%if isinstance( param, DataToolParameter ) or isinstance( param, DataCollectionToolParameter ):
%if ( prefix + param.name ) in step.input_connections_by_name:
@@ -93,19 +93,19 @@
%><div class="toolForm">
%if tool:
- <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name}</div>
+ <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name | h}</div><div class="toolFormBody">
${do_inputs( tool.inputs, step.state.inputs, "", step )}
</div>
%else:
- <div class="toolFormTitle">Step ${int(step.order_index)+1}: Unknown Tool with id '${step.tool_id}'</div>
+ <div class="toolFormTitle">Step ${int(step.order_index)+1}: Unknown Tool with id '${step.tool_id | h}'</div>
%endif
</div>
%else:
## TODO: always input dataset?
<% module = step.module %><div class="toolForm">
- <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${module.name}</div>
+ <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${module.name | h}</div><div class="toolFormBody">
${do_inputs( module.get_runtime_inputs(), step.state.inputs, "", step )}
</div>
https://bitbucket.org/galaxy/galaxy-central/commits/8d095b5e0826/
Changeset: 8d095b5e0826
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize workflow name in message when extracting workflow from history.
Affected #: 1 file
diff -r 76da60bbe585f19fc968ba2aa4a5e226c02cd92e -r 8d095b5e0826b73abba81488fbd2a7f96e5327e0 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -1228,7 +1228,7 @@
# Index page with message
workflow_id = trans.security.encode_id( stored_workflow.id )
return trans.show_message( 'Workflow "%s" created from current history. You can <a href="%s" target="_parent">edit</a> or <a href="%s">run</a> the workflow.' %
- ( workflow_name, url_for( controller='workflow', action='editor', id=workflow_id ),
+ ( escape( workflow_name ), url_for( controller='workflow', action='editor', id=workflow_id ),
url_for( controller='workflow', action='run', id=workflow_id ) ) )
@web.expose
https://bitbucket.org/galaxy/galaxy-central/commits/e739a6399e17/
Changeset: e739a6399e17
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize workflow name in myexperiment export.
On the off chance that XML file ever gets interpreted as HTML. Shouldn't hurt anything for well behaved workflow names.
Affected #: 1 file
diff -r 8d095b5e0826b73abba81488fbd2a7f96e5327e0 -r e739a6399e177e45856bf0d80170628c0c0b4b04 templates/webapps/galaxy/workflow/myexp_export.mako
--- a/templates/webapps/galaxy/workflow/myexp_export.mako
+++ b/templates/webapps/galaxy/workflow/myexp_export.mako
@@ -9,7 +9,7 @@
## Generate request.
<?xml version="1.0"?><workflow>
- <title>${workflow_name}</title>
+ <title>${workflow_name | h}</title><description>${workflow_description}</description><type>Galaxy</type><content encoding="base64" type="binary">
https://bitbucket.org/galaxy/galaxy-central/commits/9b1a9ef2d8d0/
Changeset: 9b1a9ef2d8d0
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize tool id, name, and version during workflow import.
Affected #: 1 file
diff -r e739a6399e177e45856bf0d80170628c0c0b4b04 -r 9b1a9ef2d8d0342e458e460e95f0bdad8fd7d85c lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -1125,7 +1125,7 @@
message += "You can likely install the required tools from one of the Galaxy tool sheds listed below.<br/>"
for missing_tool_tup in missing_tool_tups:
missing_tool_id, missing_tool_name, missing_tool_version = missing_tool_tup
- message += "<b>Tool name</b> %s, <b>id</b> %s, <b>version</b> %s<br/>" % ( missing_tool_name, missing_tool_id, missing_tool_version )
+ message += "<b>Tool name</b> %s, <b>id</b> %s, <b>version</b> %s<br/>" % ( escape( missing_tool_name ), escape( missing_tool_id ), escape( missing_tool_version ) )
message += "<br/>"
for shed_name, shed_url in trans.app.tool_shed_registry.tool_sheds.items():
if shed_url.endswith( '/' ):
https://bitbucket.org/galaxy/galaxy-central/commits/e830ab78a2ce/
Changeset: e830ab78a2ce
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: More sanitization while handling fields from an imported workflow.
Affected #: 1 file
diff -r 9b1a9ef2d8d0342e458e460e95f0bdad8fd7d85c -r e830ab78a2ce408523da03ae9a3d2677ba7c6d5f lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -1135,7 +1135,7 @@
url += '&tool_id='
for missing_tool_tup in missing_tool_tups:
missing_tool_id = missing_tool_tup[0]
- url += '%s,' % missing_tool_id
+ url += '%s,' % escape( missing_tool_id )
message += '<a href="%s">%s</a><br/>' % ( url, shed_name )
status = 'error'
if installed_repository_file or tool_shed_url:
https://bitbucket.org/galaxy/galaxy-central/commits/368ae981718f/
Changeset: 368ae981718f
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: More sanitizing of workflow name and tool information during import.
Affected #: 1 file
diff -r e830ab78a2ce408523da03ae9a3d2677ba7c6d5f -r 368ae981718f9c0dc98c641598723d3a75616fe3 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -1111,7 +1111,7 @@
message += "Imported, but this workflow contains cycles. "
status = "error"
else:
- message += "Workflow <b>%s</b> imported successfully. " % workflow.name
+ message += "Workflow <b>%s</b> imported successfully. " % escape( workflow.name )
if missing_tool_tups:
if trans.user_is_admin():
# A required tool is not available in the local Galaxy instance.
@@ -1155,13 +1155,13 @@
pass
if tool_shed_url:
# We've received the textual representation of a workflow from a Galaxy tool shed.
- message = "Workflow <b>%s</b> imported successfully." % workflow.name
+ message = "Workflow <b>%s</b> imported successfully." % escape( workflow.name )
url = '%s/workflow/view_workflow?repository_metadata_id=%s&workflow_name=%s&message=%s' % \
( tool_shed_url, repository_metadata_id, encoding_util.tool_shed_encode( workflow_name ), message )
return trans.response.send_redirect( url )
elif installed_repository_file:
# The workflow was read from a file included with an installed tool shed repository.
- message = "Workflow <b>%s</b> imported successfully." % workflow.name
+ message = "Workflow <b>%s</b> imported successfully." % escape( workflow.name )
if cntrller == 'api':
return status, message
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
https://bitbucket.org/galaxy/galaxy-central/commits/883191fe0d52/
Changeset: 883191fe0d52
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize workflow name and tool ids when running workflow with missing tools.
Affected #: 1 file
diff -r 368ae981718f9c0dc98c641598723d3a75616fe3 -r 883191fe0d5226748cb01237372e73ed0293e932 templates/webapps/galaxy/workflow/missing_tools.mako
--- a/templates/webapps/galaxy/workflow/missing_tools.mako
+++ b/templates/webapps/galaxy/workflow/missing_tools.mako
@@ -1,6 +1,6 @@
<%inherit file="/base.mako"/>
-<h2>Cannot run workflow "${h.to_unicode( workflow.name )}"</h2>
+<h2>Cannot run workflow "${h.to_unicode( workflow.name ) | h}"</h2>
%if workflow.annotation:
<div class="workflow-annotation">${workflow.annotation}</div>
@@ -11,7 +11,7 @@
<strong>This workflow utilizes tools which are unavailable, and cannot be run. Enable the tools listed below, or <a href="${h.url_for(controller='workflow', action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">edit the workflow</a> to correct these errors.</strong><br/><ul>
%for i, tool in enumerate( missing_tools ):
- <li>${tool}</li>
+ <li>${tool | h}</li>
%endfor
</ul></div>
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/f7c388aa4f64/
Changeset: f7c388aa4f64
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: Sanitize incoming workflow annotations during imports.
Affected #: 1 file
diff -r 883191fe0d5226748cb01237372e73ed0293e932 -r f7c388aa4f6492b0411028d69a853d8d9e6978c7 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1671,7 +1671,8 @@
stored.user = trans.user
stored.published = publish
if data[ 'annotation' ]:
- self.add_item_annotation( trans.sa_session, stored.user, stored, data[ 'annotation' ] )
+ annotation = sanitize_html( data[ 'annotation' ], 'utf-8', 'text/html' )
+ self.add_item_annotation( trans.sa_session, stored.user, stored, annotation )
# Persist
trans.sa_session.add( stored )
https://bitbucket.org/galaxy/galaxy-central/commits/0effe518ca21/
Changeset: 0effe518ca21
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:25+00:00
Summary: More workflow template sanitization during rename, copy, delete.
Affected #: 2 files
diff -r f7c388aa4f6492b0411028d69a853d8d9e6978c7 -r 0effe518ca213468e071b0e22c6e6e7276cbc40c lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -437,7 +437,7 @@
stored.latest_workflow.name = san_new_name
trans.sa_session.flush()
# For current workflows grid:
- trans.set_message( "Workflow renamed to '%s'." % new_name )
+ trans.set_message( "Workflow renamed to '%s'." % san_new_name )
return self.list( trans )
# For new workflows grid:
#message = "Workflow renamed to '%s'." % new_name
@@ -557,7 +557,7 @@
session.add( new_stored )
session.flush()
# Display the management page
- trans.set_message( 'Created new workflow with name "%s"' % new_stored.name )
+ trans.set_message( 'Created new workflow with name "%s"' % escape( new_stored.name ) )
return self.list( trans )
@web.expose
@@ -604,7 +604,7 @@
trans.sa_session.add( stored )
trans.sa_session.flush()
# Display the management page
- trans.set_message( "Workflow '%s' deleted" % stored.name )
+ trans.set_message( "Workflow '%s' deleted" % escape( stored.name ) )
return self.list( trans )
@web.expose
diff -r f7c388aa4f6492b0411028d69a853d8d9e6978c7 -r 0effe518ca213468e071b0e22c6e6e7276cbc40c templates/webapps/galaxy/workflow/rename.mako
--- a/templates/webapps/galaxy/workflow/rename.mako
+++ b/templates/webapps/galaxy/workflow/rename.mako
@@ -15,7 +15,7 @@
%endif
<div class="toolForm">
- <div class="toolFormTitle">Rename workflow '${stored.name}'</div>
+ <div class="toolFormTitle">Rename workflow '${stored.name | h}'</div><div class="toolFormBody"><form action="${h.url_for(controller='workflow', action='rename', id=trans.security.encode_id(stored.id) )}" method="POST"><div class="form-row">
@@ -23,7 +23,7 @@
New name
</label><div style="float: left; width: 250px; margin-right: 10px;">
- <input type="text" name="new_name" value="${stored.name}" size="40">
+ <input type="text" name="new_name" value="${stored.name | h}" size="40"></div><div style="clear: both"></div></div>
https://bitbucket.org/galaxy/galaxy-central/commits/66dc08787b6f/
Changeset: 66dc08787b6f
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize all values in configure_menu.mako.
Affected #: 1 file
diff -r 0effe518ca213468e071b0e22c6e6e7276cbc40c -r 66dc08787b6feff55473bf1e032ce4517d28bb42 templates/webapps/galaxy/workflow/configure_menu.mako
--- a/templates/webapps/galaxy/workflow/configure_menu.mako
+++ b/templates/webapps/galaxy/workflow/configure_menu.mako
@@ -1,4 +1,5 @@
<%inherit file="/webapps/galaxy/base_panels.mako"/>
+<%page expression_filter="h"/><%def name="init()"><%
https://bitbucket.org/galaxy/galaxy-central/commits/118df7eb098f/
Changeset: 118df7eb098f
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize workflow names in tool menu.
Affected #: 1 file
diff -r 66dc08787b6feff55473bf1e032ce4517d28bb42 -r 118df7eb098f83191b70d32a290becf9753160bf templates/webapps/galaxy/root/tool_menu.mako
--- a/templates/webapps/galaxy/root/tool_menu.mako
+++ b/templates/webapps/galaxy/root/tool_menu.mako
@@ -82,7 +82,7 @@
%if t.user.stored_workflow_menu_entries:
%for m in t.user.stored_workflow_menu_entries:
<div class="toolTitle">
- <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(m.stored_workflow_id) )}" target="galaxy_main">${ util.unicodify( m.stored_workflow.name ) }</a>
+ <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(m.stored_workflow_id) )}" target="galaxy_main">${ util.unicodify( m.stored_workflow.name ) | h}</a></div>
%endfor
%endif
https://bitbucket.org/galaxy/galaxy-central/commits/6d94a32edcd7/
Changeset: 6d94a32edcd7
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize workflow and dataset names in run_complete.mako.
Affected #: 1 file
diff -r 118df7eb098f83191b70d32a290becf9753160bf -r 6d94a32edcd7c07f2ff9b14b651745092671a0e2 templates/webapps/galaxy/workflow/run_complete.mako
--- a/templates/webapps/galaxy/workflow/run_complete.mako
+++ b/templates/webapps/galaxy/workflow/run_complete.mako
@@ -1,4 +1,5 @@
<%inherit file="/base.mako"/>
+<%page expression_filter="h"/><div class="donemessagelarge">
Successfully ran workflow "${util.unicodify( workflow.name )}". The following datasets have been added to the queue:
@@ -6,7 +7,7 @@
<div class="workflow-invocation-complete">
%if invocation['new_history']:
<p>These datasets will appear in a new history:
- <a target='galaxy_history' href="${h.url_for( controller='history', action='list', operation="Switch", id=trans.security.encode_id(invocation['new_history'].id), use_panels=False, show_deleted=False )}">
+ <a target='galaxy_history' href="${h.url_for( controller='history', action='list', operation="Switch", id=trans.security.encode_id(invocation['new_history'].id), use_panels=False, show_deleted=False ) | n}">
'${h.to_unicode(invocation['new_history'].name)}'.
</a></p>
%endif
https://bitbucket.org/galaxy/galaxy-central/commits/a9475110d9bc/
Changeset: a9475110d9bc
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize values in switching data parameter form.
Affected #: 1 file
diff -r 6d94a32edcd7c07f2ff9b14b651745092671a0e2 -r a9475110d9bcf52edc445de0ce5f66fecdc29e5b lib/galaxy/web/form_builder.py
--- a/lib/galaxy/web/form_builder.py
+++ b/lib/galaxy/web/form_builder.py
@@ -563,7 +563,7 @@
html += '<input name="__switch_default__" type="hidden" value="%s" />' % self.default_field
options = []
for name, delegate_field in self.delegate_fields.items():
- field = dumps( delegate_field.to_dict() )
+ field = escape( dumps( delegate_field.to_dict() ) )
option = " '%s': %s" % ( name, field )
options.append( option )
html += '<script>$(document).ready( function() {\nvar switchOptions = {\n'
https://bitbucket.org/galaxy/galaxy-central/commits/de60fe1e52fe/
Changeset: de60fe1e52fe
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitization for workflows_for_run.mako.
Affected #: 1 file
diff -r a9475110d9bcf52edc445de0ce5f66fecdc29e5b -r de60fe1e52fe56611629775affe698768f460581 templates/webapps/galaxy/workflow/list_for_run.mako
--- a/templates/webapps/galaxy/workflow/list_for_run.mako
+++ b/templates/webapps/galaxy/workflow/list_for_run.mako
@@ -36,7 +36,7 @@
%for i, workflow in enumerate( workflows ):
<tr><td>
- <a href="${h.url_for(controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${h.to_unicode( workflow.name )}</a>
+ <a href="${h.url_for(controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${h.to_unicode( workflow.name ) | h}</a><a id="wf-${i}-popup" class="popup-arrow" style="display: none;">▼</a></td><td>${len(workflow.latest_workflow.steps)}</td>
@@ -64,10 +64,10 @@
<% workflow = association.stored_workflow %><tr><td>
- <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
+ <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name | h}</a><a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a></td>
- <td>${workflow.user.email}</td>
+ <td>${workflow.user.email | h}</td><td>${len(workflow.latest_workflow.steps)}</td></tr>
%endfor
https://bitbucket.org/galaxy/galaxy-central/commits/293f3ff27dcb/
Changeset: 293f3ff27dcb
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize user e-mail in workflow sharing actions.
Affected #: 1 file
diff -r de60fe1e52fe56611629775affe698768f460581 -r 293f3ff27dcb5f5b22d6dea3ac7274a309f0c36b lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -311,14 +311,14 @@
.first()
if not other:
mtype = "error"
- msg = ( "User '%s' does not exist" % email )
+ msg = ( "User '%s' does not exist" % escape( email ) )
elif other == trans.get_user():
mtype = "error"
msg = ( "You cannot share a workflow with yourself" )
elif trans.sa_session.query( model.StoredWorkflowUserShareAssociation ) \
.filter_by( user=other, stored_workflow=stored ).count() > 0:
mtype = "error"
- msg = ( "Workflow already shared with '%s'" % email )
+ msg = ( "Workflow already shared with '%s'" % escape( email ) )
else:
share = model.StoredWorkflowUserShareAssociation()
share.stored_workflow = stored
@@ -326,7 +326,7 @@
session = trans.sa_session
session.add( share )
session.flush()
- trans.set_message( "Workflow '%s' shared with user '%s'" % ( stored.name, other.email ) )
+ trans.set_message( "Workflow '%s' shared with user '%s'" % ( escape( stored.name ), escape( other.email ) ) )
return trans.response.send_redirect( url_for( controller='workflow', action='sharing', id=id ) )
return trans.fill_template( "/ind_share_base.mako",
message=msg,
https://bitbucket.org/galaxy/galaxy-central/commits/70403d601043/
Changeset: 70403d601043
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: One last fix for workflow/list.mako.
Affected #: 1 file
diff -r 293f3ff27dcb5f5b22d6dea3ac7274a309f0c36b -r 70403d6010438350b3762a562bdfdd6846d91ea2 templates/webapps/galaxy/workflow/list.mako
--- a/templates/webapps/galaxy/workflow/list.mako
+++ b/templates/webapps/galaxy/workflow/list.mako
@@ -94,7 +94,7 @@
<% workflow = association.stored_workflow %><tr><td>
- <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${h.to_unicode( workflow.name )}</a>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${h.to_unicode( workflow.name ) | h}</a></td><td>${workflow.user.email}</td><td>${len(workflow.latest_workflow.steps)}</td>
https://bitbucket.org/galaxy/galaxy-central/commits/341c3a853e28/
Changeset: 341c3a853e28
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Some comments to clarify working santization.
Affected #: 2 files
diff -r 70403d6010438350b3762a562bdfdd6846d91ea2 -r 341c3a853e28fb1177d5e212ef4a3220eba4fbdc lib/galaxy/security/validate_user_input.py
--- a/lib/galaxy/security/validate_user_input.py
+++ b/lib/galaxy/security/validate_user_input.py
@@ -1,3 +1,9 @@
+"""
+Utilities for validating inputs related to user objects.
+
+The validate_* methods in this file return simple messages that do not contain
+user inputs - so these methods do not need to be escaped.
+"""
import logging
import re
diff -r 70403d6010438350b3762a562bdfdd6846d91ea2 -r 341c3a853e28fb1177d5e212ef4a3220eba4fbdc lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -2581,6 +2581,8 @@
def set_public_username( self, trans, id, username, **kwargs ):
""" Set user's public username and delegate to sharing() """
user = trans.get_user()
+ # message from validate_publicname does not contain input, no need
+ # to escape.
message = validate_publicname( trans, username, user )
if message:
return trans.fill_template( '/sharing_base.mako', item=self.get_item( trans, id ), message=message, status='error' )
https://bitbucket.org/galaxy/galaxy-central/commits/f88707a93008/
Changeset: f88707a93008
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize error message when unsharing history.
Affected #: 1 file
diff -r 341c3a853e28fb1177d5e212ef4a3220eba4fbdc -r f88707a930087d82a2a9bd63b73d5f62887c2d86 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -659,7 +659,9 @@
for husa in husas:
trans.sa_session.delete( husa )
if not deleted_sharing_relation:
- message = "History '%s' does not seem to be shared with user '%s'" % ( history.name, user.email )
+ history_name = escape( history.name )
+ user_email = escape( user.email )
+ message = "History '%s' does not seem to be shared with user '%s'" % ( history_name, user_email )
return trans.fill_template( '/sharing_base.mako', item=history,
message=message, status='error' )
https://bitbucket.org/galaxy/galaxy-central/commits/8d8e43126e48/
Changeset: 8d8e43126e48
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: More sanitization of tool ids during tool related activities.
Affected #: 1 file
diff -r f88707a930087d82a2a9bd63b73d5f62887c2d86 -r 8d8e43126e48e21546794ed5ff50beae5e6fe41a lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -66,6 +66,7 @@
from galaxy.util.template import fill_template
from galaxy.web import url_for
from galaxy.web.form_builder import SelectField
+from galaxy.web.framework.helpers import escape
from galaxy.model.item_attrs import Dictifiable
from galaxy.model import Workflow
from tool_shed.util import common_util
@@ -734,7 +735,7 @@
success = True
# Make sure the tool is actually loaded.
if tool_id not in self.tools_by_id:
- return None, False, "No tool with id %s" % tool_id
+ return None, False, "No tool with id %s" % escape( tool_id )
else:
tool = self.tools_by_id[ tool_id ]
tarball_files = []
@@ -843,7 +844,7 @@
replace the old tool.
"""
if tool_id not in self.tools_by_id:
- message = "No tool with id %s" % tool_id
+ message = "No tool with id %s" % escape( tool_id )
status = 'error'
else:
old_tool = self.tools_by_id[ tool_id ]
@@ -880,7 +881,7 @@
Attempt to remove the tool identified by 'tool_id'.
"""
if tool_id not in self.tools_by_id:
- message = "No tool with id %s" % tool_id
+ message = "No tool with id %s" % escape( tool_id )
status = 'error'
else:
tool = self.tools_by_id[ tool_id ]
https://bitbucket.org/galaxy/galaxy-central/commits/e461da2d5b6e/
Changeset: e461da2d5b6e
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: Sanitize user generated values in tool_executed.mako.
Affected #: 1 file
diff -r 8d8e43126e48e21546794ed5ff50beae5e6fe41a -r e461da2d5b6e8596297a19b93da107fe18bd449e templates/webapps/galaxy/tool_executed.mako
--- a/templates/webapps/galaxy/tool_executed.mako
+++ b/templates/webapps/galaxy/tool_executed.mako
@@ -61,7 +61,7 @@
${jobs_str} been successfully added to the queue - resulting in the following ${datasets_str}:
</p>
%for _, data in out_data:
- <div style="padding: 10px"><b> ${data.hid}: ${data.name}</b></div>
+ <div style="padding: 10px"><b> ${data.hid}: ${data.name | h}</b></div>
%endfor
<p>
@@ -83,7 +83,7 @@
<ul><!-- Styling on this list is a little flat. Consider identing these error messages. -->
%for job_error in job_errors:
- <li><b>${job_error}</b></li>
+ <li><b>${job_error | h}</b></li>
%endfor
</ul></div>
https://bitbucket.org/galaxy/galaxy-central/commits/6619aac23f9b/
Changeset: 6619aac23f9b
Branch: stable
User: jmchilton
Date: 2014-12-08 16:11:26+00:00
Summary: More sanitization related to sharing objects.
Affected #: 4 files
diff -r e461da2d5b6e8596297a19b93da107fe18bd449e -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 lib/galaxy/webapps/galaxy/controllers/page.py
--- a/lib/galaxy/webapps/galaxy/controllers/page.py
+++ b/lib/galaxy/webapps/galaxy/controllers/page.py
@@ -499,14 +499,14 @@
.first()
if not other:
mtype = "error"
- msg = ( "User '%s' does not exist" % email )
+ msg = ( "User '%s' does not exist" % escape( email ) )
elif other == trans.get_user():
mtype = "error"
msg = ( "You cannot share a page with yourself" )
elif trans.sa_session.query( model.PageUserShareAssociation ) \
.filter_by( user=other, page=page ).count() > 0:
mtype = "error"
- msg = ( "Page already shared with '%s'" % email )
+ msg = ( "Page already shared with '%s'" % escape( email ) )
else:
share = model.PageUserShareAssociation()
share.page = page
@@ -515,7 +515,9 @@
session.add( share )
self.create_item_slug( session, page )
session.flush()
- trans.set_message( "Page '%s' shared with user '%s'" % ( page.title, other.email ) )
+ page_title = escape( page.title )
+ other_email = escape( other.email )
+ trans.set_message( "Page '%s' shared with user '%s'" % ( page_title, other_email ) )
return trans.response.send_redirect( url_for( controller='page', action='sharing', id=id ) )
return trans.fill_template( "/ind_share_base.mako",
message = msg,
diff -r e461da2d5b6e8596297a19b93da107fe18bd449e -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -535,14 +535,14 @@
.first()
if not other:
mtype = "error"
- msg = ( "User '%s' does not exist" % email )
+ msg = ( "User '%s' does not exist" % escape( email ) )
elif other == trans.get_user():
mtype = "error"
msg = ( "You cannot share a visualization with yourself" )
elif trans.sa_session.query( model.VisualizationUserShareAssociation ) \
.filter_by( user=other, visualization=visualization ).count() > 0:
mtype = "error"
- msg = ( "Visualization already shared with '%s'" % email )
+ msg = ( "Visualization already shared with '%s'" % escape( email ) )
else:
share = model.VisualizationUserShareAssociation()
share.visualization = visualization
@@ -551,7 +551,9 @@
session.add( share )
self.create_item_slug( session, visualization )
session.flush()
- trans.set_message( "Visualization '%s' shared with user '%s'" % ( visualization.title, other.email ) )
+ viz_title = escape( visualization.title )
+ other_email = escape( other.email )
+ trans.set_message( "Visualization '%s' shared with user '%s'" % ( viz_title, other_email ) )
return trans.response.send_redirect( web.url_for(controller='visualization', action='sharing', id=id ) )
return trans.fill_template( "/ind_share_base.mako",
message = msg,
diff -r e461da2d5b6e8596297a19b93da107fe18bd449e -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 templates/embed_base.mako
--- a/templates/embed_base.mako
+++ b/templates/embed_base.mako
@@ -51,7 +51,7 @@
</div><h4><a class="toggle-embed" href="${display_href}" title="Show or hide ${item_display_name} content">Galaxy ${get_class_display_name( item.__class__ )} | ${get_item_name( item ) | h}</a></h4>
%if hasattr( item, "annotation") and item.annotation:
- <div class="annotation">${item.annotation}</div>
+ <div class="annotation">${item.annotation | h}</div>
%endif
## Use a hidden var to store the ajax URL for getting an item's content.
diff -r e461da2d5b6e8596297a19b93da107fe18bd449e -r 6619aac23f9bfe8d5ef59dc188359044e2ae25f7 templates/ind_share_base.mako
--- a/templates/ind_share_base.mako
+++ b/templates/ind_share_base.mako
@@ -91,7 +91,7 @@
Email address of user to share with
</label><div style="float: left; width: 250px; margin-right: 10px;">
- <input type="text" name="email" value="${email}" size="40">
+ <input type="text" name="email" value="${email | h}" size="40"></div><div style="clear: both"></div></div>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Remove seemingly unused message cruft in workflow list_for_run.mako.
by commits-noreply@bitbucket.org 08 Dec '14
by commits-noreply@bitbucket.org 08 Dec '14
08 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a8b8961827ec/
Changeset: a8b8961827ec
User: jmchilton
Date: 2014-12-08 16:02:03+00:00
Summary: Remove seemingly unused message cruft in workflow list_for_run.mako.
Affected #: 1 file
diff -r 222404d100db80657e22dbcc9b51147563b19973 -r a8b8961827ec2475a20748f5151bd96c49566e98 templates/webapps/galaxy/workflow/list_for_run.mako
--- a/templates/webapps/galaxy/workflow/list_for_run.mako
+++ b/templates/webapps/galaxy/workflow/list_for_run.mako
@@ -2,19 +2,6 @@
<%def name="title()">Workflow home</%def>
-%if message:
-<%
- try:
- messagetype
- except:
- messagetype = "done"
-%>
-<p />
-<div class="${messagetype}message">
- ${message}
-</div>
-%endif
-
<h2>Your workflows</h2><ul class="manage-table-actions">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/caebda8c654a/
Changeset: caebda8c654a
Branch: next-stable
User: carlfeberhard
Date: 2014-12-08 15:11:44+00:00
Summary: Fix to history_contents, dataset.url: use legacy route to prevent intermittent url_for GenerationException
Affected #: 1 file
diff -r 0a0dc401129472073a93a095ced211179ff1c5a4 -r caebda8c654aa079b68be736879df61c75f23faf lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -154,7 +154,11 @@
'resubmitted': hda._state == trans.app.model.Dataset.states.RESUBMITTED,
'hid' : hda.hid,
'history_content_type' : hda.history_content_type,
- 'url' : url_for( 'history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset" ),
+ #'url' : url_for( 'history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset" ),
+ #TODO: this intermittently causes a routes.GenerationException - temp use the legacy route to prevent this
+ # see also: https://trello.com/c/5d6j4X5y
+ # see also: https://sentry.galaxyproject.org/galaxy/galaxy-main/group/20769/events/9352…
+ 'url' : url_for( 'history_content', history_id=encoded_history_id, id=encoded_id ),
}
def __collection_dict( self, trans, dataset_collection_instance, view="collection" ):
https://bitbucket.org/galaxy/galaxy-central/commits/222404d100db/
Changeset: 222404d100db
User: carlfeberhard
Date: 2014-12-08 15:12:00+00:00
Summary: merge
Affected #: 1 file
diff -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 -r 222404d100db80657e22dbcc9b51147563b19973 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -154,7 +154,11 @@
'resubmitted': hda._state == trans.app.model.Dataset.states.RESUBMITTED,
'hid' : hda.hid,
'history_content_type' : hda.history_content_type,
- 'url' : url_for( 'history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset" ),
+ #'url' : url_for( 'history_content_typed', history_id=encoded_history_id, id=encoded_id, type="dataset" ),
+ #TODO: this intermittently causes a routes.GenerationException - temp use the legacy route to prevent this
+ # see also: https://trello.com/c/5d6j4X5y
+ # see also: https://sentry.galaxyproject.org/galaxy/galaxy-main/group/20769/events/9352…
+ 'url' : url_for( 'history_content', history_id=encoded_history_id, id=encoded_id ),
}
def __collection_dict( self, trans, dataset_collection_instance, view="collection" ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
8 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e8400d6f1dc3/
Changeset: e8400d6f1dc3
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Drop psu_production stuff from scripts/functional_tests.py.
These tests need to runnable against running servers but should be more general and updated.
Affected #: 1 file
diff -r 690ea2dc6cab18cdacfcd59ba0e5c2178df2bff4 -r e8400d6f1dc31cf8f63d00922231b66dbc83f300 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -256,78 +256,33 @@
database_auto_migrate = False
galaxy_test_proxy_port = None
- psu_production = False
if start_server:
- if 'GALAXY_TEST_PSU_PRODUCTION' in os.environ:
- if not galaxy_test_port:
- raise Exception( 'Please set GALAXY_TEST_PORT to the port to which the proxy server will proxy' )
- galaxy_test_proxy_port = os.environ.get( 'GALAXY_TEST_PROXY_PORT', None )
- if not galaxy_test_proxy_port:
- raise Exception( 'Please set GALAXY_TEST_PROXY_PORT to the port on which the proxy server is listening' )
- base_file_path = os.environ.get( 'GALAXY_TEST_BASE_FILE_PATH', None )
- if not base_file_path:
- raise Exception( 'Please set GALAXY_TEST_BASE_FILE_PATH to the directory which will contain the dataset files directory' )
- base_new_file_path = os.environ.get( 'GALAXY_TEST_BASE_NEW_FILE_PATH', None )
- if not base_new_file_path:
- raise Exception( 'Please set GALAXY_TEST_BASE_NEW_FILE_PATH to the directory which will contain the temporary directory' )
- database_connection = os.environ.get( 'GALAXY_TEST_DBURI', None )
- if not database_connection:
- raise Exception( 'Please set GALAXY_TEST_DBURI to the URI of the database to be used for tests' )
- nginx_upload_store = os.environ.get( 'GALAXY_TEST_NGINX_UPLOAD_STORE', None )
- if not nginx_upload_store:
- raise Exception( 'Please set GALAXY_TEST_NGINX_UPLOAD_STORE to the path where the nginx upload module places uploaded files' )
- tool_config_file = 'tool_conf.xml.main'
- default_cluster_job_runner = os.environ.get( 'GALAXY_TEST_DEFAULT_CLUSTER_JOB_RUNNER', 'pbs:///' )
- file_path = tempfile.mkdtemp( dir=base_file_path )
- new_file_path = tempfile.mkdtemp( dir=base_new_file_path )
- cluster_files_directory = os.path.join( new_file_path, 'pbs' )
- job_working_directory = os.path.join( new_file_path, 'job_working_directory' )
- os.mkdir( cluster_files_directory )
- os.mkdir( job_working_directory )
- kwargs = dict( database_engine_option_pool_size='10',
- database_engine_option_max_overflow='20',
- database_engine_option_strategy='threadlocal',
- nginx_x_accel_redirect_base='/_x_accel_redirect',
- nginx_upload_store=nginx_upload_store,
- nginx_upload_path='/_upload',
- allow_library_path_paste='True',
- cluster_files_directory=cluster_files_directory,
- job_working_directory=job_working_directory,
- outputs_to_working_directory='True',
- static_enabled='False',
- debug='False',
- track_jobs_in_database='True',
- job_scheduler_policy='FIFO',
- start_job_runners='pbs',
- default_cluster_job_runner=default_cluster_job_runner )
- psu_production = True
+ tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
+ # Configure the database path.
+ if 'GALAXY_TEST_DBPATH' in os.environ:
+ galaxy_db_path = os.environ[ 'GALAXY_TEST_DBPATH' ]
else:
- tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
- # Configure the database path.
- if 'GALAXY_TEST_DBPATH' in os.environ:
- galaxy_db_path = os.environ[ 'GALAXY_TEST_DBPATH' ]
- else:
- galaxy_db_path = os.path.join( tempdir, 'database' )
- # Configure the paths Galaxy needs to test tools.
- file_path = os.path.join( galaxy_db_path, 'files' )
- new_file_path = tempfile.mkdtemp( prefix='new_files_path_', dir=tempdir )
- job_working_directory = tempfile.mkdtemp( prefix='job_working_directory_', dir=tempdir )
- install_database_connection = os.environ.get( 'GALAXY_TEST_INSTALL_DBURI', None )
- if 'GALAXY_TEST_DBURI' in os.environ:
- database_connection = os.environ['GALAXY_TEST_DBURI']
- else:
- db_path = os.path.join( galaxy_db_path, 'universe.sqlite' )
- if 'GALAXY_TEST_DB_TEMPLATE' in os.environ:
- # Middle ground between recreating a completely new
- # database and pointing at existing database with
- # GALAXY_TEST_DBURI. The former requires a lot of setup
- # time, the latter results in test failures in certain
- # cases (namely tool shed tests expecting clean database).
- log.debug( "Copying database template from %s.", os.environ['GALAXY_TEST_DB_TEMPLATE'] )
- __copy_database_template(os.environ['GALAXY_TEST_DB_TEMPLATE'], db_path)
- database_auto_migrate = True
- database_connection = 'sqlite:///%s' % db_path
- kwargs = {}
+ galaxy_db_path = os.path.join( tempdir, 'database' )
+ # Configure the paths Galaxy needs to test tools.
+ file_path = os.path.join( galaxy_db_path, 'files' )
+ new_file_path = tempfile.mkdtemp( prefix='new_files_path_', dir=tempdir )
+ job_working_directory = tempfile.mkdtemp( prefix='job_working_directory_', dir=tempdir )
+ install_database_connection = os.environ.get( 'GALAXY_TEST_INSTALL_DBURI', None )
+ if 'GALAXY_TEST_DBURI' in os.environ:
+ database_connection = os.environ['GALAXY_TEST_DBURI']
+ else:
+ db_path = os.path.join( galaxy_db_path, 'universe.sqlite' )
+ if 'GALAXY_TEST_DB_TEMPLATE' in os.environ:
+ # Middle ground between recreating a completely new
+ # database and pointing at existing database with
+ # GALAXY_TEST_DBURI. The former requires a lot of setup
+ # time, the latter results in test failures in certain
+ # cases (namely tool shed tests expecting clean database).
+ log.debug( "Copying database template from %s.", os.environ['GALAXY_TEST_DB_TEMPLATE'] )
+ __copy_database_template(os.environ['GALAXY_TEST_DB_TEMPLATE'], db_path)
+ database_auto_migrate = True
+ database_connection = 'sqlite:///%s' % db_path
+ kwargs = {}
for dir in file_path, new_file_path:
try:
if not os.path.exists( dir ):
@@ -376,8 +331,6 @@
)
if install_database_connection is not None:
kwargs[ 'install_database_connection' ] = install_database_connection
- if psu_production:
- kwargs[ 'global_conf' ] = None
if not database_connection.startswith( 'sqlite://' ):
kwargs[ 'database_engine_option_max_overflow' ] = '20'
kwargs[ 'database_engine_option_pool_size' ] = '10'
@@ -448,12 +401,6 @@
time.sleep( 0.1 )
else:
raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
- # Test if the proxy server is up
- if psu_production:
- conn = httplib.HTTPConnection( galaxy_test_host, galaxy_test_proxy_port ) # directly test the app, not the proxy
- conn.request( "GET", "/" )
- if not conn.getresponse().status == 200:
- raise Exception( "Test HTTP proxy server did not return '200 OK'" )
log.info( "Embedded web server started" )
# ---- Load toolbox for generated tests -----------------------------------
# We don't add the tests to the path until everything is up and running
@@ -571,14 +518,6 @@
log.info( "GALAXY_TEST_NO_CLEANUP is on. Temporary files in %s" % tempdir )
except:
pass
- if psu_production and 'GALAXY_TEST_NO_CLEANUP' not in os.environ:
- for dir in ( file_path, new_file_path ):
- try:
- if os.path.exists( dir ):
- log.info( 'Cleaning up temporary files in %s' % dir )
- shutil.rmtree( dir )
- except:
- pass
if success:
return 0
else:
https://bitbucket.org/galaxy/galaxy-central/commits/ad012fc04856/
Changeset: ad012fc04856
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Remove redundant lines in scripts/functional_tests.py.
This stuff is already imported at the top of the file - my guess is the need to import it later is not longer needed.
Affected #: 1 file
diff -r e8400d6f1dc31cf8f63d00922231b66dbc83f300 -r ad012fc04856b1423378f2309a9e02bdfbcdf360 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -402,11 +402,6 @@
else:
raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
log.info( "Embedded web server started" )
- # ---- Load toolbox for generated tests -----------------------------------
- # We don't add the tests to the path until everything is up and running
- new_path = [ os.path.join( cwd, "test" ) ]
- new_path.extend( sys.path[1:] )
- sys.path = new_path
# ---- Find tests ---------------------------------------------------------
if galaxy_test_proxy_port:
https://bitbucket.org/galaxy/galaxy-central/commits/bcae5db5956a/
Changeset: bcae5db5956a
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Reduce some duplication related to nose running.
Affected #: 4 files
diff -r ad012fc04856b1423378f2309a9e02bdfbcdf360 -r bcae5db5956ac836c90ee0e2f14f8b901606c86b scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -54,6 +54,7 @@
from functional import database_contexts
from base.api_util import get_master_api_key
from base.api_util import get_user_api_key
+from base.nose_util import run
import nose.core
import nose.config
@@ -160,18 +161,7 @@
def run_tests( test_config ):
- loader = nose.loader.TestLoader( config=test_config )
- plug_loader = test_config.plugins.prepareTestLoader( loader )
- if plug_loader is not None:
- loader = plug_loader
- tests = loader.loadTestsFromNames( test_config.testNames )
- test_runner = nose.core.TextTestRunner( stream=test_config.stream,
- verbosity=test_config.verbosity,
- config=test_config )
- plug_runner = test_config.plugins.prepareTestRunner( test_runner )
- if plug_runner is not None:
- test_runner = plug_runner
- return test_runner.run( tests )
+ return run( test_config )
def __copy_database_template( source, db_path ):
diff -r ad012fc04856b1423378f2309a9e02bdfbcdf360 -r bcae5db5956ac836c90ee0e2f14f8b901606c86b test/base/nose_util.py
--- /dev/null
+++ b/test/base/nose_util.py
@@ -0,0 +1,32 @@
+""" Utilities for dealing with nose.
+
+There was some duplication between Galaxy, Tool Shed, and Install/Test,
+trying to reduce that here.
+"""
+
+try:
+ from galaxy import eggs
+ eggs.require( "nose" )
+except ImportError:
+ pass
+import nose
+
+
+def run( test_config, plugins=[] ):
+ loader = nose.loader.TestLoader( config=test_config )
+ for plugin in plugins:
+ test_config.plugins.addPlugin( plugin )
+ plug_loader = test_config.plugins.prepareTestLoader( loader )
+ if plug_loader is not None:
+ loader = plug_loader
+ tests = loader.loadTestsFromNames( test_config.testNames )
+ test_runner = nose.core.TextTestRunner(
+ stream=test_config.stream,
+ verbosity=test_config.verbosity,
+ config=test_config
+ )
+ plug_runner = test_config.plugins.prepareTestRunner( test_runner )
+ if plug_runner is not None:
+ test_runner = plug_runner
+ result = test_runner.run( tests )
+ return result
diff -r ad012fc04856b1423378f2309a9e02bdfbcdf360 -r bcae5db5956ac836c90ee0e2f14f8b901606c86b test/install_and_test_tool_shed_repositories/base/util.py
--- a/test/install_and_test_tool_shed_repositories/base/util.py
+++ b/test/install_and_test_tool_shed_repositories/base/util.py
@@ -1058,6 +1058,10 @@
return base_url
def run_tests( test_config ):
+ ## TODO: replace whole method with...
+ # from base import nose_util
+ # result = nose_util.run( test_config, plugins=[ new ReportResults() ] )
+ # return result, test_config.plugins._plugins
loader = nose.loader.TestLoader( config=test_config )
test_config.plugins.addPlugin( ReportResults() )
plug_loader = test_config.plugins.prepareTestLoader( loader )
diff -r ad012fc04856b1423378f2309a9e02bdfbcdf360 -r bcae5db5956ac836c90ee0e2f14f8b901606c86b test/tool_shed/functional_tests.py
--- a/test/tool_shed/functional_tests.py
+++ b/test/tool_shed/functional_tests.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+from __future__ import absolute_import
import os
import sys
@@ -66,6 +67,7 @@
from functional import database_contexts
+from base import nose_util
log = logging.getLogger( "tool_shed_functional_tests.py" )
@@ -147,19 +149,10 @@
</data_managers>
'''
+
def run_tests( test_config ):
- loader = nose.loader.TestLoader( config=test_config )
- plug_loader = test_config.plugins.prepareTestLoader( loader )
- if plug_loader is not None:
- loader = plug_loader
- tests = loader.loadTestsFromNames( test_config.testNames )
- test_runner = nose.core.TextTestRunner( stream=test_config.stream,
- verbosity=test_config.verbosity,
- config=test_config )
- plug_runner = test_config.plugins.prepareTestRunner( test_runner )
- if plug_runner is not None:
- test_runner = plug_runner
- return test_runner.run( tests )
+ return nose_util.run( test_config )
+
def main():
# ---- Configuration ------------------------------------------------------
https://bitbucket.org/galaxy/galaxy-central/commits/c33f0de648fc/
Changeset: c33f0de648fc
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Remove unused method now that twill interactor is gone.
Affected #: 1 file
diff -r bcae5db5956ac836c90ee0e2f14f8b901606c86b -r c33f0de648fc6cbbeedcc75afe1dc36f74ace89f test/base/twilltestcase.py
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1771,20 +1771,6 @@
tc.submit( "reset_user_password_button" )
self.check_page_for_string( "Passwords reset for 1 user." )
- def run_tool( self, tool_id, repeat_name=None, **kwd ):
- """Runs the tool 'tool_id' and passes it the key/values from the *kwd"""
- params = dict( tool_id=tool_id )
- self.visit_url( "/tool_runner/index", params )
- # Must click somewhere in tool_form, to disambiguate what form
- # is being targetted.
- tc.browser.clicked( tc.browser.get_form( 'tool_form' ), None )
- if repeat_name is not None:
- repeat_button = '%s_add' % repeat_name
- # Submit the "repeat" form button to add an input)
- tc.submit( repeat_button )
- tc.find( 'runtool_btn' )
- self.submit_form( **kwd )
-
def run_ucsc_main( self, track_params, output_params ):
"""Gets Data From UCSC"""
tool_id = "ucsc_table_direct1"
https://bitbucket.org/galaxy/galaxy-central/commits/bc3432c21cc7/
Changeset: bc3432c21cc7
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Adjust test/functional/test_data_managers.py for run_tool ret val change in 21e3d69.
Affected #: 1 file
diff -r c33f0de648fc6cbbeedcc75afe1dc36f74ace89f -r bc3432c21cc75ff1ac5aa8ac8445ab80b95b7f94 test/functional/test_data_managers.py
--- a/test/functional/test_data_managers.py
+++ b/test/functional/test_data_managers.py
@@ -27,7 +27,7 @@
stage_data_in_history( galaxy_interactor, testdef.test_data(), test_history, shed_tool_id )
- data_list = galaxy_interactor.run_tool( testdef, test_history ) #test_history will have inputs only, outputs are placed in the specialized data manager history
+ galaxy_interactor.run_tool( testdef, test_history ) #test_history will have inputs only, outputs are placed in the specialized data manager history
#FIXME: Move history determination and switching into the interactor
data_manager_history = None
https://bitbucket.org/galaxy/galaxy-central/commits/ccd35e79ac1f/
Changeset: ccd35e79ac1f
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Slightly improved error message for tool tests if job submission fails.
Affected #: 1 file
diff -r bc3432c21cc75ff1ac5aa8ac8445ab80b95b7f94 -r ccd35e79ac1fbe89acd55bf3c95978bc30c5c2e9 test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -212,7 +212,8 @@
try:
return self.__dictify_outputs( submit_response_object ), submit_response_object[ 'jobs' ]
except KeyError:
- raise Exception( submit_response_object[ 'message' ] )
+ message = "Error creating a job for these tool inputs - %s" % submit_response_object[ 'message' ]
+ raise Exception( message )
def _create_collection( self, history_id, collection_def ):
create_payload = dict(
https://bitbucket.org/galaxy/galaxy-central/commits/38b2fa3d3e49/
Changeset: 38b2fa3d3e49
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Give admins more data via the jobs API.
More raw information about job metrics and the command-line (visible to them via the UI).
Affected #: 1 file
diff -r ccd35e79ac1fbe89acd55bf3c95978bc30c5c2e9 -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 lib/galaxy/webapps/galaxy/api/jobs.py
--- a/lib/galaxy/webapps/galaxy/api/jobs.py
+++ b/lib/galaxy/webapps/galaxy/api/jobs.py
@@ -103,9 +103,20 @@
if full_output:
job_dict.update( dict( stderr=job.stderr, stdout=job.stdout ) )
if trans.user_is_admin():
+ job_dict['command_line'] = job.command_line
def metric_to_dict(metric):
- return dict(zip(['title', 'value'], trans.app.job_metrics.format(metric.plugin, metric.metric_name, metric.metric_value)))
+ metric_name = metric.metric_name
+ metric_value = metric.metric_value
+ metric_plugin = metric.plugin
+ title, value = trans.app.job_metrics.format(metric_plugin, metric_name, metric_value)
+ return dict(
+ title=title,
+ value=value,
+ plugin=metric_plugin,
+ name=metric_name,
+ raw_value=str(metric_value),
+ )
job_dict['job_metrics'] = [metric_to_dict(metric) for metric in job.metrics]
return job_dict
https://bitbucket.org/galaxy/galaxy-central/commits/896c18ca6b2f/
Changeset: 896c18ca6b2f
User: jmchilton
Date: 2014-12-08 05:21:47+00:00
Summary: Implement structured tool test data.
Rather than relying solely on exceptions back to nose/test framework - add option (--structured_data_report_file) to run_tests.sh that causes a bunch of detailed data to be dumped to the specified file in a very structured way. Includes full to_dict of the job from the API which in turn includes job metrics, command-line, job's standard error and outputs (instead of the test frameworks), as well as the tool inputs, and exceptions broken out for tool execution versus output checking.
Its all indexed in the file by the test id (without the actual test toolbox depending on knowing the test id) - so one could pair this information with the XUnit output to produce much more detailed breakdowns of the tests.
Affected #: 5 files
diff -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 run_tests.sh
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -47,6 +47,7 @@
test_script="./scripts/functional_tests.py"
report_file="run_functional_tests.html"
xunit_report_file=""
+structured_data_report_file=""
with_framework_test_tools_arg=""
driver="python"
@@ -156,6 +157,15 @@
exit 1
fi
;;
+ --structured_data_report_file)
+ if [ $# -gt 1 ]; then
+ structured_data_report_file=$2
+ shift 2
+ else
+ echo "--structured_data_report_file requires an argument" 1>&2
+ exit 1
+ fi
+ ;;
-c|--coverage)
# Must have coverage installed (try `which coverage`) - only valid with --unit
# for now. Would be great to get this to work with functional tests though.
@@ -249,7 +259,12 @@
else
xunit_args=""
fi
- python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $xunit_args $with_framework_test_tools_arg $extra_args
+ if [ -n "$structured_data_report_file" ]; then
+ structured_data_args="--with-structureddata --structured-data-file $structured_data_report_file"
+ else
+ structured_data_args=""
+ fi
+ python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $xunit_args $structured_data_args $with_framework_test_tools_arg $extra_args
else
ensure_grunt
if [ -n "$watch" ]; then
diff -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -55,6 +55,7 @@
from base.api_util import get_master_api_key
from base.api_util import get_user_api_key
from base.nose_util import run
+from base.instrument import StructuredTestDataPlugin
import nose.core
import nose.config
@@ -439,6 +440,7 @@
user_api_key=get_user_api_key(),
)
test_config = nose.config.Config( env=os.environ, ignoreFiles=ignore_files, plugins=nose.plugins.manager.DefaultPluginManager() )
+ test_config.plugins.addPlugin( StructuredTestDataPlugin() )
test_config.configure( sys.argv )
result = run_tests( test_config )
success = result.wasSuccessful()
diff -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 test/base/instrument.py
--- /dev/null
+++ b/test/base/instrument.py
@@ -0,0 +1,89 @@
+""" Utilities to help instrument tool tests.
+
+Including structed data nose plugin that allows storing arbitrary structured
+data on a per test case basis - used by tool test to store inputs,
+output problems, job tests, etc... but could easily by used by other test
+types in a different way.
+"""
+
+import json
+import threading
+
+try:
+ from galaxy import eggs
+ eggs.require( "nose" )
+except ImportError:
+ pass
+
+
+from nose.plugins import Plugin
+
+NO_JOB_DATA = object()
+JOB_DATA = threading.local()
+JOB_DATA.new = True
+JOB_DATA.data = NO_JOB_DATA
+
+
+def register_job_data(data):
+ if not JOB_DATA.new:
+ return
+ JOB_DATA.data = data
+ JOB_DATA.new = False
+
+
+def fetch_job_data():
+ try:
+ if JOB_DATA.new:
+ return NO_JOB_DATA
+ else:
+ return JOB_DATA.data
+ finally:
+ JOB_DATA.new = True
+
+
+class StructuredTestDataPlugin( Plugin ):
+ name = 'structureddata'
+
+ def options(self, parser, env):
+ super(StructuredTestDataPlugin, self).options(parser, env=env)
+ parser.add_option(
+ '--structured-data-file', action='store',
+ dest='structured_data_file', metavar="FILE",
+ default=env.get('NOSE_STRUCTURED_DATA', 'structured_test_data.json'),
+ help=("Path to JSON file to store the Galaxy structured data report in."
+ "Default is structured_test_data.json in the working directory "
+ "[NOSE_STRUCTURED_DATA]"))
+
+ def configure(self, options, conf):
+ super(StructuredTestDataPlugin, self).configure(options, conf)
+ self.conf = conf
+ if not self.enabled:
+ return
+ self.tests = []
+ self.structured_data_report_file = open(options.structured_data_file, 'w')
+
+ def finalize(self, result):
+ pass
+
+ def _handle_result(self, test, *args, **kwds):
+ job_data = fetch_job_data()
+ id = test.id()
+ has_data = job_data is not NO_JOB_DATA
+ entry = {
+ 'id': id,
+ 'has_data': has_data,
+ 'data': job_data if has_data else None,
+ }
+ self.tests.append(entry)
+
+ addError = _handle_result
+ addFailure = _handle_result
+ addSuccess = _handle_result
+
+ def report(self, stream):
+ report_obj = {
+ 'version': '0.1',
+ 'tests': self.tests,
+ }
+ json.dump(report_obj, self.structured_data_report_file)
+ self.structured_data_report_file.close()
diff -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -6,6 +6,7 @@
eggs.require( "requests" )
from galaxy import util
from galaxy.util.odict import odict
+from galaxy.util.bunch import Bunch
from requests import get
from requests import post
from json import dumps
@@ -210,10 +211,14 @@
submit_response = self.__submit_tool( history_id, tool_id=testdef.tool.id, tool_input=inputs_tree )
submit_response_object = submit_response.json()
try:
- return self.__dictify_outputs( submit_response_object ), submit_response_object[ 'jobs' ]
+ return Bunch(
+ inputs=inputs_tree,
+ outputs=self.__dictify_outputs( submit_response_object ),
+ jobs=submit_response_object[ 'jobs' ],
+ )
except KeyError:
message = "Error creating a job for these tool inputs - %s" % submit_response_object[ 'message' ]
- raise Exception( message )
+ raise RunToolException( message, inputs_tree )
def _create_collection( self, history_id, collection_def ):
create_payload = dict(
@@ -404,6 +409,13 @@
return get( url, params=data )
+class RunToolException(Exception):
+
+ def __init__(self, message, inputs=None):
+ super(RunToolException, self).__init__(message)
+ self.inputs = inputs
+
+
GALAXY_INTERACTORS = {
'api': GalaxyInteractorApi,
}
diff -r 38b2fa3d3e4973e40998215fae6a9b14d1fecf71 -r 896c18ca6b2f1922f73fc74ba9f2bb6229fb54a1 test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -1,7 +1,8 @@
import new
import sys
from base.twilltestcase import TwillTestCase
-from base.interactor import build_interactor, stage_data_in_history
+from base.interactor import build_interactor, stage_data_in_history, RunToolException
+from base.instrument import register_job_data
from galaxy.tools import DataManagerTool
from galaxy.util import bunch
import logging
@@ -34,10 +35,48 @@
stage_data_in_history( galaxy_interactor, testdef.test_data(), test_history, shed_tool_id )
- data_list, jobs = galaxy_interactor.run_tool( testdef, test_history )
- self.assertTrue( data_list )
+ # Once data is ready, run the tool and check the outputs - record API
+ # input, job info, tool run exception, as well as exceptions related to
+ # job output checking and register they with the test plugin so it can
+ # record structured information.
+ tool_inputs = None
+ job_stdio = None
+ job_output_exceptions = None
+ tool_execution_exception = None
+ try:
+ try:
+ tool_response = galaxy_interactor.run_tool( testdef, test_history )
+ data_list, jobs, tool_inputs = tool_response.outputs, tool_response.jobs, tool_response.inputs
+ except RunToolException as e:
+ tool_inputs = e.inputs
+ tool_execution_exception = e
+ raise e
+ except Exception as e:
+ tool_execution_exception = e
+ raise e
- self._verify_outputs( testdef, test_history, jobs, shed_tool_id, data_list, galaxy_interactor )
+ self.assertTrue( data_list )
+
+ try:
+ job_stdio = self._verify_outputs( testdef, test_history, jobs, shed_tool_id, data_list, galaxy_interactor )
+ except JobOutputsError as e:
+ job_stdio = e.job_stdio
+ job_output_exceptions = e.output_exceptions
+ raise e
+ except Exception as e:
+ job_output_exceptions = [e]
+ raise e
+ finally:
+ job_data = {}
+ if tool_inputs is not None:
+ job_data["inputs"] = tool_inputs
+ if job_stdio is not None:
+ job_data["job"] = job_stdio
+ if job_output_exceptions:
+ job_data["output_problems"] = map(str, job_output_exceptions)
+ if tool_execution_exception:
+ job_data["execution_problem"] = str(tool_execution_exception)
+ register_job_data(job_data)
galaxy_interactor.delete_history( test_history )
@@ -63,6 +102,7 @@
raise Exception( message )
found_exceptions = []
+ job_stdio = None
for output_index, output_tuple in enumerate(testdef.outputs):
# Get the correct hid
name, outfile, attributes = output_tuple
@@ -89,9 +129,22 @@
if stream in job_stdio:
print >>sys.stderr, self._format_stream( job_stdio[ stream ], stream=stream, format=True )
found_exceptions.append(e)
+ if job_stdio is None:
+ job_stdio = galaxy_interactor.get_job_stdio( jobs[0][ 'id' ] )
+
if found_exceptions:
- big_message = "\n".join(map(str, found_exceptions))
- raise AssertionError(big_message)
+ raise JobOutputsError(found_exceptions, job_stdio)
+ else:
+ return job_stdio
+
+
+class JobOutputsError(AssertionError):
+
+ def __init__(self, output_exceptions, job_stdio):
+ big_message = "\n".join(map(str, output_exceptions))
+ super(JobOutputsError, self).__init__(big_message)
+ self.job_stdio = job_stdio
+ self.output_exceptions = output_exceptions
@nottest
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Add --xunit_report_file option to run_tests.sh.
by commits-noreply@bitbucket.org 06 Dec '14
by commits-noreply@bitbucket.org 06 Dec '14
06 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/690ea2dc6cab/
Changeset: 690ea2dc6cab
User: jmchilton
Date: 2014-12-06 05:14:20+00:00
Summary: Add --xunit_report_file option to run_tests.sh.
If supplied - python based tests will output a xunit style test to the specified file.
Affected #: 1 file
diff -r 34ed52176b054166d687c3a402391f0d40f339db -r 690ea2dc6cab18cdacfcd59ba0e5c2178df2bff4 run_tests.sh
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -46,6 +46,7 @@
test_script="./scripts/functional_tests.py"
report_file="run_functional_tests.html"
+xunit_report_file=""
with_framework_test_tools_arg=""
driver="python"
@@ -146,6 +147,15 @@
exit 1
fi
;;
+ --xunit_report_file)
+ if [ $# -gt 1 ]; then
+ xunit_report_file=$2
+ shift 2
+ else
+ echo "--xunit_report_file requires an argument" 1>&2
+ exit 1
+ fi
+ ;;
-c|--coverage)
# Must have coverage installed (try `which coverage`) - only valid with --unit
# for now. Would be great to get this to work with functional tests though.
@@ -234,7 +244,12 @@
fi
if [ "$driver" = "python" ]; then
- python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $with_framework_test_tools_arg $extra_args
+ if [ -n "$xunit_report_file" ]; then
+ xunit_args="--with-xunit --xunit-file $xunit_report_file"
+ else
+ xunit_args=""
+ fi
+ python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $xunit_args $with_framework_test_tools_arg $extra_args
else
ensure_grunt
if [ -n "$watch" ]; then
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/45653ba49df7/
Changeset: 45653ba49df7
User: jmchilton
Date: 2014-12-06 04:35:44+00:00
Summary: Include diffs for all errors when testing - don't stop at first.
Gives more details to aid testing (especially for tools with lots of outputs) and lets developer collect all correct test data files at once (when GALAXY_TEST_SAVE is set or using `planemo test` with --job_output_files argument) instead of needing to rerun the tool repeatedly.
Affected #: 1 file
diff -r e2bfb1e6e3c5845e4e1518e620dcf7fbcdc21a0c -r 45653ba49df7fb353dfd3dd4f9d30111818ff60b test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -61,6 +61,8 @@
messaage_template = "Incorrect number of outputs - expected %d, found %s."
message = messaage_template % ( expected, actual )
raise Exception( message )
+ found_exceptions = []
+
for output_index, output_tuple in enumerate(testdef.outputs):
# Get the correct hid
name, outfile, attributes = output_tuple
@@ -78,13 +80,18 @@
self.assertTrue( output_data is not None )
try:
galaxy_interactor.verify_output( history, jobs, output_data, output_testdef=output_testdef, shed_tool_id=shed_tool_id, maxseconds=maxseconds )
- except Exception:
- for job in jobs:
- job_stdio = galaxy_interactor.get_job_stdio( job[ 'id' ] )
- for stream in ['stdout', 'stderr']:
- if stream in job_stdio:
- print >>sys.stderr, self._format_stream( job_stdio[ stream ], stream=stream, format=True )
- raise
+ except Exception as e:
+ if not found_exceptions:
+ # Only print this stuff out once.
+ for job in jobs:
+ job_stdio = galaxy_interactor.get_job_stdio( job[ 'id' ] )
+ for stream in ['stdout', 'stderr']:
+ if stream in job_stdio:
+ print >>sys.stderr, self._format_stream( job_stdio[ stream ], stream=stream, format=True )
+ found_exceptions.append(e)
+ if found_exceptions:
+ big_message = "\n".join(map(str, found_exceptions))
+ raise AssertionError(big_message)
@nottest
https://bitbucket.org/galaxy/galaxy-central/commits/34ed52176b05/
Changeset: 34ed52176b05
User: jmchilton
Date: 2014-12-06 04:35:44+00:00
Summary: Twill interactor for tests is broken - so I am deleting.
It wasn't long for this world with a JavaScript tool form anyway - would be nice to implement a casperjs driven interactor though so the UI could be exercised for tests.
Affected #: 1 file
diff -r 45653ba49df7fb353dfd3dd4f9d30111818ff60b -r 34ed52176b054166d687c3a402391f0d40f339db test/base/interactor.py
--- a/test/base/interactor.py
+++ b/test/base/interactor.py
@@ -1,15 +1,11 @@
import os
import re
from StringIO import StringIO
-from galaxy.tools.parameters import grouping
from galaxy.tools import test
from galaxy import eggs
eggs.require( "requests" )
from galaxy import util
from galaxy.util.odict import odict
-import galaxy.model
-from galaxy.model.orm import and_, desc
-from functional import database_contexts
from requests import get
from requests import post
from json import dumps
@@ -407,120 +403,6 @@
return get( url, params=data )
-class GalaxyInteractorTwill( object ):
-
- def __init__( self, twill_test_case ):
- self.twill_test_case = twill_test_case
-
- def verify_output( self, history, output_data, output_testdef, shed_tool_id, maxseconds ):
- outfile = output_testdef.outfile
- attributes = output_testdef.attributes
-
- hid = output_data.get( 'hid' )
- self.twill_test_case.verify_dataset_correctness( outfile, hid=hid, attributes=attributes, shed_tool_id=shed_tool_id, maxseconds=maxseconds )
-
- def get_job_stream( self, history_id, output_data, stream ):
- data_id = self.twill_test_case.security.encode_id( output_data.get( 'id' ) )
- return self.twill_test_case._get_job_stream_output( data_id, stream=stream, format=False )
-
- def stage_data_async( self, test_data, history, shed_tool_id, async=True ):
- name = test_data.get( 'name', None )
- if name:
- async = False
- self.twill_test_case.upload_file( test_data['fname'],
- ftype=test_data['ftype'],
- dbkey=test_data['dbkey'],
- metadata=test_data['metadata'],
- composite_data=test_data['composite_data'],
- shed_tool_id=shed_tool_id,
- wait=(not async) )
- if name:
- hda_id = self.twill_test_case.get_history_as_data_list()[-1].get( 'id' )
- try:
- self.twill_test_case.edit_hda_attribute_info( hda_id=str(hda_id), new_name=name )
- except:
- print "### call to edit_hda failed for hda_id %s, new_name=%s" % (hda_id, name)
- return lambda: self.twill_test_case.wait()
-
- def run_tool( self, testdef, test_history ):
- # We need to handle the case where we've uploaded a valid compressed file since the upload
- # tool will have uncompressed it on the fly.
-
- # Lose tons of information to accomodate legacy repeat handling.
- all_inputs = {}
- for key, value in testdef.inputs.iteritems():
- all_inputs[ key.split("|")[-1] ] = value
-
- # See if we have a grouping.Repeat element
- repeat_name = None
- for input_name, input_value in testdef.tool.inputs_by_page[0].items():
- if isinstance( input_value, grouping.Repeat ) and all_inputs.get( input_name, 1 ) not in [ 0, "0" ]: # default behavior is to test 1 repeat, for backwards compatibility
- if not input_value.min: # If input_value.min == 1, the element is already on the page don't add new element.
- repeat_name = input_name
- break
-
- #check if we need to verify number of outputs created dynamically by tool
- if testdef.tool.force_history_refresh:
- job_finish_by_output_count = len( self.twill_test_case.get_history_as_data_list() )
- else:
- job_finish_by_output_count = False
-
- inputs_tree = testdef.inputs
- # # # HACK: Flatten single-value lists. Required when using expand_grouping
- # #for key, value in inputs_tree.iteritems():
- # if isinstance(value, list) and len(value) == 1:
- # inputs_tree[key] = value[0]
-
- # Strip out just a given page of inputs from inputs "tree".
- def filter_page_inputs( n ):
- page_input_keys = testdef.tool.inputs_by_page[ n ].keys()
- return dict( [ (k, v) for k, v in inputs_tree.iteritems() if k.split("|")[0] or k.split("|")[0].resplit("_", 1)[0] in page_input_keys ] )
-
- # Do the first page
- page_inputs = filter_page_inputs( 0 )
-
- # Run the tool
- self.twill_test_case.run_tool( testdef.tool.id, repeat_name=repeat_name, **page_inputs )
- print "page_inputs (0)", page_inputs
- # Do other pages if they exist
- for i in range( 1, testdef.tool.npages ):
- page_inputs = filter_page_inputs( i )
- self.twill_test_case.submit_form( **page_inputs )
- print "page_inputs (%i)" % i, page_inputs
-
- # Check the results ( handles single or multiple tool outputs ). Make sure to pass the correct hid.
- # The output datasets from the tool should be in the same order as the testdef.outputs.
- data_list = None
- while data_list is None:
- data_list = self.twill_test_case.get_history_as_data_list()
- if job_finish_by_output_count and len( testdef.outputs ) > ( len( data_list ) - job_finish_by_output_count ):
- data_list = None
- return data_list
-
- def new_history( self ):
- # Start with a new history
- self.twill_test_case.logout()
- self.twill_test_case.login( email='test(a)bx.psu.edu' )
- admin_user = database_contexts.galaxy_context.query( galaxy.model.User ).filter( galaxy.model.User.table.c.email == 'test(a)bx.psu.edu' ).one()
- self.twill_test_case.new_history()
- latest_history = database_contexts.galaxy_context.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.deleted == False,
- galaxy.model.History.table.c.user_id == admin_user.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- assert latest_history is not None, "Problem retrieving latest_history from database"
- if len( self.twill_test_case.get_hids_in_history( self.twill_test_case.get_latest_history()[ 'id' ] ) ) > 0:
- raise AssertionError("ToolTestCase.do_it failed to create a new empty history")
- return latest_history
-
- def delete_history( self, latest_history ):
- self.twill_test_case.delete_history( id=self.twill_test_case.security.encode_id( latest_history.id ) )
-
- def output_hid( self, output_data ):
- return output_data.get( 'hid' )
-
-
GALAXY_INTERACTORS = {
'api': GalaxyInteractorApi,
- 'twill': GalaxyInteractorTwill,
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0a0dc4011294/
Changeset: 0a0dc4011294
Branch: next-stable
User: jmchilton
Date: 2014-12-06 04:30:52+00:00
Summary: Mark test_toolbox:build_tests as "not a test".
This will prevent run_tests.sh from picking up the extra test when running full test tool box - the way planemo does (i.e. this fixes the problem where planemo always runs one extra passing test).
Affected #: 1 file
diff -r c906eacc8d543384ad84b87f34e6b515fc695bcd -r 0a0dc401129472073a93a095ced211179ff1c5a4 test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -5,6 +5,11 @@
from galaxy.tools import DataManagerTool
from galaxy.util import bunch
import logging
+try:
+ from nose.tools import nottest
+except ImportError:
+ nottest = lambda x: x
+
log = logging.getLogger( __name__ )
toolbox = None
@@ -82,6 +87,7 @@
raise
+@nottest
def build_tests( app=None, testing_shed_tools=False, master_api_key=None, user_api_key=None ):
"""
If the module level variable `toolbox` is set, generate `ToolTestCase`
https://bitbucket.org/galaxy/galaxy-central/commits/e2bfb1e6e3c5/
Changeset: e2bfb1e6e3c5
User: jmchilton
Date: 2014-12-06 04:31:48+00:00
Summary: Merge next-stable.
Affected #: 1 file
diff -r 79cea2ce170e61db6afd6d249379b96cf353f15b -r e2bfb1e6e3c5845e4e1518e620dcf7fbcdc21a0c test/functional/test_toolbox.py
--- a/test/functional/test_toolbox.py
+++ b/test/functional/test_toolbox.py
@@ -5,6 +5,11 @@
from galaxy.tools import DataManagerTool
from galaxy.util import bunch
import logging
+try:
+ from nose.tools import nottest
+except ImportError:
+ nottest = lambda x: x
+
log = logging.getLogger( __name__ )
toolbox = None
@@ -82,6 +87,7 @@
raise
+@nottest
def build_tests( app=None, testing_shed_tools=False, master_api_key=None, user_api_key=None ):
"""
If the module level variable `toolbox` is set, generate `ToolTestCase`
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c906eacc8d54/
Changeset: c906eacc8d54
Branch: next-stable
User: jmchilton
Date: 2014-12-06 02:16:03+00:00
Summary: ... and not all select params have static_options attribute.
Bug fixes for bug fixes - why do I even try?
Affected #: 1 file
diff -r 7114d15a6d2234cb895d058e0e44c86f373c49b2 -r c906eacc8d543384ad84b87f34e6b515fc695bcd lib/galaxy/tools/test.py
--- a/lib/galaxy/tools/test.py
+++ b/lib/galaxy/tools/test.py
@@ -202,7 +202,7 @@
for ( name, value, extra ) in collection_def.collect_inputs():
require_file( name, value, extra, self.required_files )
processed_value = collection_def
- elif isinstance( value, basic.SelectToolParameter ):
+ elif isinstance( value, basic.SelectToolParameter ) and hasattr( value, 'static_options' ):
# Tests may specify values as either raw value or the value
# as they appear in the list - the API doesn't and shouldn't
# accept the text value - so we need to convert the text
https://bitbucket.org/galaxy/galaxy-central/commits/79cea2ce170e/
Changeset: 79cea2ce170e
User: jmchilton
Date: 2014-12-06 02:16:13+00:00
Summary: Merge next-stable.
Affected #: 1 file
diff -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 -r 79cea2ce170e61db6afd6d249379b96cf353f15b lib/galaxy/tools/test.py
--- a/lib/galaxy/tools/test.py
+++ b/lib/galaxy/tools/test.py
@@ -202,7 +202,7 @@
for ( name, value, extra ) in collection_def.collect_inputs():
require_file( name, value, extra, self.required_files )
processed_value = collection_def
- elif isinstance( value, basic.SelectToolParameter ):
+ elif isinstance( value, basic.SelectToolParameter ) and hasattr( value, 'static_options' ):
# Tests may specify values as either raw value or the value
# as they appear in the list - the API doesn't and shouldn't
# accept the text value - so we need to convert the text
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7114d15a6d22/
Changeset: 7114d15a6d22
Branch: next-stable
User: jmchilton
Date: 2014-12-06 01:35:22+00:00
Summary: Twill tool tests allowed selects specified by display text instead of value.
This didn't work for API tests - restore this functionality and add test case in test/functional/tools/multi_select.xml to verify this behavior is correct.
Affected #: 2 files
diff -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 -r 7114d15a6d2234cb895d058e0e44c86f373c49b2 lib/galaxy/tools/test.py
--- a/lib/galaxy/tools/test.py
+++ b/lib/galaxy/tools/test.py
@@ -196,12 +196,37 @@
if not isinstance(param_value, list):
param_value = [ param_value ]
processed_value = [ self.__add_uploaded_dataset( context.for_state(), v, param_extra, value ) for v in param_value ]
- if isinstance( value, basic.DataCollectionToolParameter ):
+ elif isinstance( value, basic.DataCollectionToolParameter ):
assert 'collection' in param_extra
collection_def = param_extra[ 'collection' ]
for ( name, value, extra ) in collection_def.collect_inputs():
require_file( name, value, extra, self.required_files )
processed_value = collection_def
+ elif isinstance( value, basic.SelectToolParameter ):
+ # Tests may specify values as either raw value or the value
+ # as they appear in the list - the API doesn't and shouldn't
+ # accept the text value - so we need to convert the text
+ # into the form value.
+ def process_param_value( param_value ):
+ found_value = False
+ value_for_text = None
+ if value.static_options:
+ for (text, opt_value, selected) in value.static_options:
+ if param_value == opt_value:
+ found_value = True
+ if value_for_text is None and param_value == text:
+ value_for_text = opt_value
+ if not found_value and value_for_text is not None:
+ processed_value = value_for_text
+ else:
+ processed_value = param_value
+ return processed_value
+ # Do replacement described above for lists or singleton
+ # values.
+ if isinstance( param_value, list ):
+ processed_value = map( process_param_value, param_value )
+ else:
+ processed_value = process_param_value( param_value )
else:
processed_value = param_value
expanded_inputs[ context.for_state() ] = processed_value
diff -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 -r 7114d15a6d2234cb895d058e0e44c86f373c49b2 test/functional/tools/multi_select.xml
--- a/test/functional/tools/multi_select.xml
+++ b/test/functional/tools/multi_select.xml
@@ -25,5 +25,13 @@
</assert_contents></output></test>
+ <test>
+ <param name="select_ex" value="Ex1" />
+ <output name="output">
+ <assert_contents>
+ <has_line line="--ex1" />
+ </assert_contents>
+ </output>
+ </test></tests></tool>
https://bitbucket.org/galaxy/galaxy-central/commits/719191cd0f3e/
Changeset: 719191cd0f3e
User: jmchilton
Date: 2014-12-06 01:36:48+00:00
Summary: Merge next-stable.
Affected #: 31 files
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 client/galaxy/scripts/galaxy.library.js
--- a/client/galaxy/scripts/galaxy.library.js
+++ b/client/galaxy/scripts/galaxy.library.js
@@ -36,7 +36,7 @@
initialize: function() {
this.routesHit = 0;
//keep count of number of routes handled by the application
- Backbone.history.on('route', function() { this.routesHit++; }, this);
+ Backbone.history.on( 'route', function() { this.routesHit++; }, this );
},
routes: {
@@ -45,6 +45,7 @@
"library/:library_id/permissions" : "library_permissions",
"folders/:folder_id/permissions" : "folder_permissions",
"folders/:id" : "folder_content",
+ "folders/:id/page/:show_page" : "folder_page",
"folders/:folder_id/datasets/:dataset_id" : "dataset_detail",
"folders/:folder_id/datasets/:dataset_id/permissions" : "dataset_permissions",
"folders/:folder_id/datasets/:dataset_id/versions/:ldda_id" : "dataset_version",
@@ -53,13 +54,13 @@
},
back: function() {
- if(this.routesHit > 1) {
+ if( this.routesHit > 1 ) {
//more than one route hit -> user did not land to current page directly
window.history.back();
} else {
//otherwise go to the home page. Use replaceState if available so
//the navigation doesn't create an extra history entry
- this.navigate('#', {trigger:true, replace:true});
+ this.navigate( '#', { trigger:true, replace:true } );
}
}
});
@@ -71,7 +72,8 @@
with_deleted : false,
sort_order : 'asc',
sort_by : 'name',
- library_page_size : 20
+ library_page_size : 20,
+ folder_page_size : 15
}
});
@@ -94,10 +96,10 @@
this.library_router = new LibraryRouter();
- this.library_router.on('route:libraries', function() {
- Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
- Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
- });
+ this.library_router.on( 'route:libraries', function() {
+ Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
+ Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
+ });
this.library_router.on('route:libraries_page', function( show_page ) {
if ( Galaxy.libraries.libraryToolbarView === null ){
@@ -108,66 +110,77 @@
}
});
- this.library_router.on('route:folder_content', function(id) {
+ this.library_router.on( 'route:folder_content', function( id ) {
if (Galaxy.libraries.folderToolbarView){
- Galaxy.libraries.folderToolbarView.$el.unbind('click');
- }
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: id});
- });
+ Galaxy.libraries.folderToolbarView.$el.unbind( 'click' );
+ }
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id } );
+ });
- this.library_router.on('route:download', function(folder_id, format) {
- if ($('#folder_list_body').find(':checked').length === 0) {
- mod_toastr.info( 'You must select at least one dataset to download' );
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: true, replace: true});
- } else {
- Galaxy.libraries.folderToolbarView.download(folder_id, format);
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: false, replace: true});
- }
- });
+ this.library_router.on( 'route:folder_page', function( id, show_page ) {
+ if ( Galaxy.libraries.folderToolbarView === null ){
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( {id: id} );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id, show_page: show_page } );
+ } else {
+ Galaxy.libraries.folderListView.render( { id: id, show_page: parseInt( show_page ) } )
+ }
+ });
- this.library_router.on('route:dataset_detail', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
- });
- this.library_router.on('route:dataset_version', function(folder_id, dataset_id, ldda_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
- });
+ this.library_router.on( 'route:download', function( folder_id, format ) {
+ if ( $( '#folder_list_body' ).find( ':checked' ).length === 0 ) {
+ mod_toastr.info( 'You must select at least one dataset to download' );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: true, replace: true } );
+ } else {
+ Galaxy.libraries.folderToolbarView.download( folder_id, format );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: false, replace: true } );
+ }
+ });
- this.library_router.on('route:dataset_permissions', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_detail', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
+ });
- this.library_router.on('route:library_permissions', function(library_id){
- if (Galaxy.libraries.libraryView){
- Galaxy.libraries.libraryView.$el.unbind('click');
- }
- Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_version', function(folder_id, dataset_id, ldda_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
+ });
- this.library_router.on('route:folder_permissions', function(folder_id){
- if (Galaxy.libraries.folderView){
- Galaxy.libraries.folderView.$el.unbind('click');
- }
- Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
- });
- this.library_router.on('route:import_datasets', function(folder_id, source){
- if (Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView){
- Galaxy.libraries.folderToolbarView.showImportModal({source:source});
- } else {
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: folder_id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: folder_id});
- Galaxy.libraries.folderToolbarView.showImportModal({source: source});
- }
- });
+ this.library_router.on( 'route:dataset_permissions', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:library_permissions', function(library_id){
+ if (Galaxy.libraries.libraryView){
+ Galaxy.libraries.libraryView.$el.unbind('click');
+ }
+ Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:folder_permissions', function(folder_id){
+ if (Galaxy.libraries.folderView){
+ Galaxy.libraries.folderView.$el.unbind('click');
+ }
+ Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:import_datasets', function( folder_id, source ){
+ if ( Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView ){
+ Galaxy.libraries.folderToolbarView.showImportModal( { source:source } );
+ } else {
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: folder_id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: folder_id } );
+ Galaxy.libraries.folderToolbarView.showImportModal( { source: source } );
+ }
+ });
Backbone.history.start({pushState: false});
}
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 client/galaxy/scripts/mvc/library/library-folderlist-view.js
--- a/client/galaxy/scripts/mvc/library/library-folderlist-view.js
+++ b/client/galaxy/scripts/mvc/library/library-folderlist-view.js
@@ -15,322 +15,359 @@
) {
var FolderListView = Backbone.View.extend({
- el : '#folder_items_element',
- defaults: {
- 'include_deleted' : false
- },
- // progress percentage
- progress: 0,
- // progress rate per one item
- progressStep: 1,
- // self modal
- modal : null,
+ el : '#folder_items_element',
+ // progress percentage
+ progress: 0,
+ // progress rate per one item
+ progressStep: 1,
- folderContainer: null,
+ folderContainer: null,
- sort: 'asc',
+ sort: 'asc',
- events: {
- 'click #select-all-checkboxes' : 'selectAll',
- 'click .dataset_row' : 'selectClickedRow',
- 'click .sort-folder-link' : 'sortColumnClicked'
- },
+ events: {
+ 'click #select-all-checkboxes' : 'selectAll',
+ 'click .dataset_row' : 'selectClickedRow',
+ 'click .sort-folder-link' : 'sortColumnClicked'
+ },
- // cache of rendered views
- rowViews: {},
-
- initialize : function(options){
- this.options = _.defaults(this.options || {}, options);
- this.fetchFolder();
- },
+ collection: null,
- fetchFolder: function(options){
- var options = options || {};
- this.options.include_deleted = options.include_deleted;
- var that = this;
+ defaults: {
+ include_deleted: false,
+ page_count: null,
+ show_page: null
+ },
- this.collection = new mod_library_model.Folder();
+ /**
+ * Initialize and fetch the folder from the server.
+ * @param {object} options an object with options
+ */
+ initialize : function( options ){
+ this.options = _.defaults( this.options || {}, this.defaults, options );
+ this.modal = null;
+ // map of folder item ids to item views = cache
+ this.rowViews = {};
- // start to listen if someone modifies collection
- this.listenTo(this.collection, 'add', this.renderOne);
- this.listenTo(this.collection, 'remove', this.removeOne);
+ // create a collection of folder items for this view
+ this.collection = new mod_library_model.Folder();
- this.folderContainer = new mod_library_model.FolderContainer({id: this.options.id});
- this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
- if (this.options.include_deleted){
- this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
- }
- this.folderContainer.fetch({
- success: function(folder_container) {
- that.folder_container = folder_container;
- that.render();
- that.addAll(folder_container.get('folder').models);
- if (that.options.dataset_id){
- row = _.findWhere(that.rowViews, {id: that.options.dataset_id});
- if (row) {
+ // start to listen if someone modifies the collection
+ this.listenTo( this.collection, 'add', this.renderOne );
+ this.listenTo( this.collection, 'remove', this.removeOne );
+
+ this.fetchFolder();
+ },
+
+ fetchFolder: function( options ){
+ var options = options || {};
+ this.options.include_deleted = options.include_deleted;
+ var that = this;
+
+ this.folderContainer = new mod_library_model.FolderContainer( { id: this.options.id } );
+ this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
+
+ if ( this.options.include_deleted ){
+ this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
+ }
+ this.folderContainer.fetch({
+ success: function( folder_container ) {
+ that.folder_container = folder_container;
+ that.render();
+ },
+ error: function( model, response ){
+ if ( typeof response.responseJSON !== "undefined" ){
+ mod_toastr.error( response.responseJSON.err_msg + ' Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ } else {
+ mod_toastr.error( 'An error ocurred. Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ }
+ }
+ });
+ },
+
+ render: function ( options ){
+ this.options = _.extend( this.options, options );
+ var template = this.templateFolder();
+ $(".tooltip").hide();
+
+ // find the upper id in the full path
+ var path = this.folderContainer.attributes.metadata.full_path;
+ var upper_folder_id;
+ if ( path.length === 1 ){ // the library is above us
+ upper_folder_id = 0;
+ } else {
+ upper_folder_id = path[ path.length-2 ][ 0 ];
+ }
+
+ this.$el.html( template( {
+ path: this.folderContainer.attributes.metadata.full_path,
+ parent_library_id: this.folderContainer.attributes.metadata.parent_library_id,
+ id: this.options.id,
+ upper_folder_id: upper_folder_id,
+ order: this.sort
+ } ) );
+
+ // when dataset_id is present render its details too
+ if ( this.options.dataset_id ){
+ row = _.findWhere( that.rowViews, { id: this.options.dataset_id } );
+ if ( row ) {
row.showDatasetDetails();
} else {
- mod_toastr.error('Dataset not found. Showing folder instead.');
+ mod_toastr.error( 'Requested dataset not found. Showing folder instead.' );
}
+ } else {
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.paginate();
+ }
+ $("#center [data-toggle]").tooltip();
+ $("#center").css('overflow','auto');
+ },
+
+ paginate: function( options ){
+ this.options = _.extend( this.options, options );
+
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.options.total_items_count = this.folder_container.get( 'folder' ).models.length;
+ this.options.page_count = Math.ceil( this.options.total_items_count / Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ var page_start = ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * ( this.options.show_page - 1 ) );
+ var items_to_render = null;
+ items_to_render = this.folder_container.get( 'folder' ).models.slice( page_start, page_start + Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ this.options.items_shown = items_to_render.length;
+ // User requests page with no items
+ if ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * this.options.show_page > ( this.options.total_items_count + Galaxy.libraries.preferences.get( 'folder_page_size' ) ) ){
+ items_to_render = [];
+ }
+ Galaxy.libraries.folderToolbarView.renderPaginator( this.options );
+ this.collection.reset();
+ this.addAll( items_to_render )
+ },
+
+ /**
+ * Adds all given models to the collection.
+ * @param {array of Item or FolderAsModel} array of models that should
+ * be added to the view's collection.
+ */
+ addAll: function( models ){
+ _.each(models, function( model ) {
+ Galaxy.libraries.folderListView.collection.add( model );
+ });
+ $( "#center [data-toggle]" ).tooltip();
+ this.checkEmptiness();
+ this.postRender();
+ },
+
+ /**
+ * Call this after all models are added to the collection
+ * to ensure that the folder toolbar will show proper options
+ * and that event will be bound on all subviews.
+ */
+ postRender: function(){
+ var fetched_metadata = this.folderContainer.attributes.metadata;
+ fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
+ Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * Iterates this view's collection and calls the render
+ * function for each. Also binds the hover behavior.
+ */
+ renderAll: function(){
+ var that = this;
+ _.each( this.collection.models.reverse(), function( model ) {
+ that.renderOne( model );
+ });
+ this.postRender();
+ },
+
+ /**
+ * Creates a view for the given model and adds it to the folder view.
+ * @param {Item or FolderAsModel} model of the view that will be rendered
+ */
+ renderOne: function(model){
+ if (model.get('type') !== 'folder'){
+ this.options.contains_file = true;
+ // model.set('readable_size', this.size_to_string(model.get('file_size')));
}
- },
- error: function(model, response){
- if (typeof response.responseJSON !== "undefined"){
- mod_toastr.error(response.responseJSON.err_msg + ' Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- } else {
- mod_toastr.error('An error ocurred. Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- }
+ model.set('folder_id', this.id);
+ var rowView = new mod_library_folderrow_view.FolderRowView(model);
+
+ // save new rowView to cache
+ this.rowViews[model.get('id')] = rowView;
+
+ this.$el.find('#first_folder_item').after(rowView.el);
+
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * removes the view of the given model from the DOM
+ * @param {Item or FolderAsModel} model of the view that will be removed
+ */
+ removeOne: function( model ){
+ this.$el.find( '#' + model.id ).remove();
+ },
+
+ /** Checks whether the list is empty and adds/removes the message */
+ checkEmptiness : function(){
+ if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
+ this.$el.find('.empty-folder-message').show();
+ } else {
+ this.$el.find('.empty-folder-message').hide();
}
- });
- },
+ },
- render: function (options) {
- this.options = _.defaults(this.options, options);
- var template = this.templateFolder();
- $(".tooltip").hide();
+ /** User clicked the table heading = he wants to sort stuff */
+ sortColumnClicked : function(event){
+ event.preventDefault();
+ if (this.sort === 'asc'){
+ this.sortFolder('name','desc');
+ this.sort = 'desc';
+ } else {
+ this.sortFolder('name','asc');
+ this.sort = 'asc';
+ }
+ this.render();
+ this.renderAll();
+ this.checkEmptiness();
+ },
- // TODO move to server
- // find the upper id in the full path
- var path = this.folderContainer.attributes.metadata.full_path;
- var upper_folder_id;
- if (path.length === 1){ // the library is above us
- upper_folder_id = 0;
- } else {
- upper_folder_id = path[path.length-2][0];
+ /**
+ * Sorts the underlying collection according to the parameters received.
+ * Currently supports only sorting by name.
+ */
+ sortFolder: function(sort_by, order){
+ if (sort_by === 'name'){
+ if (order === 'asc'){
+ return this.collection.sortByNameAsc();
+ } else if (order === 'desc'){
+ return this.collection.sortByNameDesc();
+ }
+ }
+ },
+
+ /**
+ * User clicked the checkbox in the table heading
+ * @param {context} event
+ */
+ selectAll : function (event) {
+ var selected = event.target.checked;
+ that = this;
+ // Iterate each checkbox
+ $(':checkbox', '#folder_list_body').each(function() {
+ this.checked = selected;
+ $row = $(this.parentElement.parentElement);
+ // Change color of selected/unselected
+ if (selected) {
+ that.makeDarkRow($row);
+ } else {
+ that.makeWhiteRow($row);
+ }
+ });
+ },
+
+ /**
+ * Check checkbox if user clicks on the whole row or
+ * on the checkbox itself
+ */
+ selectClickedRow : function (event) {
+ var checkbox = '';
+ var $row;
+ var source;
+ if (event.target.localName === 'input'){
+ checkbox = event.target;
+ $row = $(event.target.parentElement.parentElement);
+ source = 'input';
+ } else if (event.target.localName === 'td') {
+ checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
+ $row = $(event.target.parentElement);
+ source = 'td';
+ }
+ if (checkbox.checked){
+ if (source==='td'){
+ checkbox.checked = '';
+ this.makeWhiteRow($row);
+ } else if (source==='input') {
+ this.makeDarkRow($row);
+ }
+ } else {
+ if (source==='td'){
+ checkbox.checked = 'selected';
+ this.makeDarkRow($row);
+ } else if (source==='input') {
+ this.makeWhiteRow($row);
+ }
+ }
+ },
+
+ makeDarkRow: function($row){
+ $row.removeClass('light').addClass('dark');
+ $row.find('a').removeClass('light').addClass('dark');
+ $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
+ },
+
+ makeWhiteRow: function($row){
+ $row.removeClass('dark').addClass('light');
+ $row.find('a').removeClass('dark').addClass('light');
+ $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
+ },
+
+ templateFolder : function (){
+ var tmpl_array = [];
+
+ // BREADCRUMBS
+ tmpl_array.push('<ol class="breadcrumb">');
+ tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
+ tmpl_array.push(' <% _.each(path, function(path_item) { %>');
+ tmpl_array.push(' <% if (path_item[0] != id) { %>');
+ tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
+ tmpl_array.push( '<% } else { %>');
+ tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</ol>');
+
+ // FOLDER CONTENT
+ tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
+ tmpl_array.push(' <thead>');
+ tmpl_array.push(' <th class="button_heading"></th>');
+ tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
+ tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
+ tmpl_array.push(' <th style="width:5%;">data type</th>');
+ tmpl_array.push(' <th style="width:10%;">size</th>');
+ tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
+ tmpl_array.push(' <th style="width:10%;"></th> ');
+ tmpl_array.push(' </thead>');
+ tmpl_array.push(' <tbody id="folder_list_body">');
+ tmpl_array.push(' <tr id="first_folder_item">');
+ tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' </tr>');
+
+ tmpl_array.push(' </tbody>');
+ tmpl_array.push('</table>');
+ tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
+
+ return _.template(tmpl_array.join(''));
}
-
- this.$el.html(template({ path: this.folderContainer.attributes.metadata.full_path, parent_library_id: this.folderContainer.attributes.metadata.parent_library_id, id: this.options.id, upper_folder_id: upper_folder_id, order: this.sort}));
-
- // initialize the library tooltips
- $("#center [data-toggle]").tooltip();
- //hack to show scrollbars
- $("#center").css('overflow','auto');
- },
-
- /**
- * Call this after all models are added to the collection
- * to ensure that the folder toolbar will show proper options
- * and that event will be bound on all subviews.
- */
- postRender: function(){
- var fetched_metadata = this.folderContainer.attributes.metadata;
- fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
- Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * Adds all given models to the collection.
- * @param {array of Item or FolderAsModel} array of models that should
- * be added to the view's collection.
- */
- addAll: function(models){
- _.each(models.reverse(), function(model) {
- Galaxy.libraries.folderListView.collection.add(model);
- });
-
- $("#center [data-toggle]").tooltip();
- this.checkEmptiness();
-
- this.postRender();
- },
-
- /**
- * Iterates this view's collection and calls the render
- * function for each. Also binds the hover behavior.
- */
- renderAll: function(){
- var that = this;
- _.each(this.collection.models.reverse(), function(model) {
- that.renderOne(model);
- });
- this.postRender();
- },
-
- /**
- * Creates a view for the given model and adds it to the folder view.
- * @param {Item or FolderAsModel} model of the view that will be rendered
- */
- renderOne: function(model){
- if (model.get('type') !== 'folder'){
- this.options.contains_file = true;
- // model.set('readable_size', this.size_to_string(model.get('file_size')));
- }
- model.set('folder_id', this.id);
- var rowView = new mod_library_folderrow_view.FolderRowView(model);
-
- // save new rowView to cache
- this.rowViews[model.get('id')] = rowView;
-
- this.$el.find('#first_folder_item').after(rowView.el);
-
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * removes the view of the given model from the DOM
- * @param {Item or FolderAsModel} model of the view that will be removed
- */
- removeOne: function(model){
- this.$el.find('#' + model.id).remove();
- },
-
- /** Checks whether the list is empty and adds/removes the message */
- checkEmptiness : function(){
- if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
- this.$el.find('.empty-folder-message').show();
- } else {
- this.$el.find('.empty-folder-message').hide();
- }
- },
-
- /** User clicked the table heading = he wants to sort stuff */
- sortColumnClicked : function(event){
- event.preventDefault();
- if (this.sort === 'asc'){
- this.sortFolder('name','desc');
- this.sort = 'desc';
- } else {
- this.sortFolder('name','asc');
- this.sort = 'asc';
- }
- this.render();
- this.renderAll();
- this.checkEmptiness();
- },
-
- /**
- * Sorts the underlying collection according to the parameters received.
- * Currently supports only sorting by name.
- */
- sortFolder: function(sort_by, order){
- if (sort_by === 'name'){
- if (order === 'asc'){
- return this.collection.sortByNameAsc();
- } else if (order === 'desc'){
- return this.collection.sortByNameDesc();
- }
- }
- },
-
- /**
- * User clicked the checkbox in the table heading
- * @param {context} event
- */
- selectAll : function (event) {
- var selected = event.target.checked;
- that = this;
- // Iterate each checkbox
- $(':checkbox', '#folder_list_body').each(function() {
- this.checked = selected;
- $row = $(this.parentElement.parentElement);
- // Change color of selected/unselected
- if (selected) {
- that.makeDarkRow($row);
- } else {
- that.makeWhiteRow($row);
- }
- });
- },
-
- /**
- * Check checkbox if user clicks on the whole row or
- * on the checkbox itself
- */
- selectClickedRow : function (event) {
- var checkbox = '';
- var $row;
- var source;
- if (event.target.localName === 'input'){
- checkbox = event.target;
- $row = $(event.target.parentElement.parentElement);
- source = 'input';
- } else if (event.target.localName === 'td') {
- checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
- $row = $(event.target.parentElement);
- source = 'td';
- }
- if (checkbox.checked){
- if (source==='td'){
- checkbox.checked = '';
- this.makeWhiteRow($row);
- } else if (source==='input') {
- this.makeDarkRow($row);
- }
- } else {
- if (source==='td'){
- checkbox.checked = 'selected';
- this.makeDarkRow($row);
- } else if (source==='input') {
- this.makeWhiteRow($row);
- }
- }
- },
-
- makeDarkRow: function($row){
- $row.removeClass('light').addClass('dark');
- $row.find('a').removeClass('light').addClass('dark');
- $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
- },
-
- makeWhiteRow: function($row){
- $row.removeClass('dark').addClass('light');
- $row.find('a').removeClass('dark').addClass('light');
- $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
- },
-
- templateFolder : function (){
- var tmpl_array = [];
-
- // BREADCRUMBS
- tmpl_array.push('<ol class="breadcrumb">');
- tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
- tmpl_array.push(' <% _.each(path, function(path_item) { %>');
- tmpl_array.push(' <% if (path_item[0] != id) { %>');
- tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
- tmpl_array.push( '<% } else { %>');
- tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</ol>');
-
- // FOLDER CONTENT
- tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
- tmpl_array.push(' <thead>');
- tmpl_array.push(' <th class="button_heading"></th>');
- tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
- tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
- tmpl_array.push(' <th style="width:5%;">data type</th>');
- tmpl_array.push(' <th style="width:10%;">size</th>');
- tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
- tmpl_array.push(' <th style="width:10%;"></th> ');
- tmpl_array.push(' </thead>');
- tmpl_array.push(' <tbody id="folder_list_body">');
- tmpl_array.push(' <tr id="first_folder_item">');
- tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' </tr>');
-
- tmpl_array.push(' </tbody>');
- tmpl_array.push('</table>');
- tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
-
- return _.template(tmpl_array.join(''));
- }
-
+
});
return {
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
--- a/client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
+++ b/client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
@@ -20,7 +20,9 @@
'click #toolbtn_bulk_import' : 'modalBulkImport',
'click #include_deleted_datasets_chk' : 'checkIncludeDeleted',
'click #toolbtn_show_libinfo' : 'showLibInfo',
- 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets'
+ 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets',
+ 'click #page_size_prompt' : 'showPageSizePrompt'
+
},
defaults: {
@@ -90,6 +92,22 @@
this.$el.html(toolbar_template(template_defaults));
},
+ /**
+ * Called from FolderListView when needed.
+ * @param {object} options common options
+ */
+ renderPaginator: function( options ){
+ this.options = _.extend( this.options, options );
+ var paginator_template = this.templatePaginator();
+ this.$el.find( '#folder_paginator' ).html( paginator_template({
+ id: this.options.id,
+ show_page: parseInt( this.options.show_page ),
+ page_count: parseInt( this.options.page_count ),
+ total_items_count: this.options.total_items_count,
+ items_shown: this.options.items_shown
+ }));
+ },
+
configureElements: function(options){
this.options = _.extend(this.options, options);
@@ -833,11 +851,11 @@
var popped_item = lddas_set.pop();
if ( typeof popped_item === "undefined" ) {
if ( this.options.chain_call_control.failed_number === 0 ){
- mod_toastr.success( 'Selected datasets deleted' );
+ mod_toastr.success( 'Selected datasets were deleted.' );
} else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
- mod_toastr.error( 'There was an error and no datasets were deleted.' );
+ mod_toastr.error( 'There was an error and no datasets were deleted. Please make sure you have sufficient permissions.' );
} else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
- mod_toastr.warning( 'Some of the datasets could not be deleted' );
+ mod_toastr.warning( 'Some of the datasets could not be deleted. Please make sure you have sufficient permissions.' );
}
Galaxy.modal.hide();
return this.deleted_lddas;
@@ -976,6 +994,14 @@
}
},
+ showPageSizePrompt: function(){
+ var folder_page_size = prompt( 'How many items per page do you want to see?', Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ if ( ( folder_page_size != null ) && ( folder_page_size == parseInt( folder_page_size ) ) ) {
+ Galaxy.libraries.preferences.set( { 'folder_page_size': parseInt( folder_page_size ) } );
+ Galaxy.libraries.folderListView.render( { id: this.options.id, show_page: 1 } );
+ }
+ },
+
templateToolBar: function(){
tmpl_array = [];
@@ -1016,7 +1042,6 @@
tmpl_array.push(' <button style="display:none;" data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button add-library-items" type="button"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');
tmpl_array.push('<% } %>');
-
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button dataset-manipulation" style="margin-left: 0.5em; display:none;" type="button"><span class="fa fa-book"></span> to History</button>');
tmpl_array.push(' <div id="toolbtn_dl" class="btn-group dataset-manipulation" style="margin-left: 0.5em; display:none; ">');
tmpl_array.push(' <button title="Download selected datasets as archive" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
@@ -1032,6 +1057,10 @@
tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show library information" id="toolbtn_show_libinfo" class="primary-button" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Library Info</button>');
tmpl_array.push(' <span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki"><a href="https://wiki.galaxyproject.org/DataLibraries/screen/FolderContents" target="_blank"><button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button></a></span>');
+ tmpl_array.push(' <span id="folder_paginator" class="library-paginator">');
+ // paginator will append here
+ tmpl_array.push(' </span>');
+
tmpl_array.push(' </div>');
// TOOLBAR END
tmpl_array.push(' <div id="folder_items_element">');
@@ -1239,7 +1268,41 @@
tmpl_array.push('</ul>');
return _.template(tmpl_array.join(''));
- }
+ },
+
+ templatePaginator: function(){
+ tmpl_array = [];
+
+ tmpl_array.push(' <ul class="pagination pagination-sm">');
+ tmpl_array.push(' <% if ( ( show_page - 1 ) > 0 ) { %>');
+ tmpl_array.push(' <% if ( ( show_page - 1 ) > page_count ) { %>'); // we are on higher page than total page count
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( show_page - 1 ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% } else { %>'); // we are on the first page
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <li class="active">');
+ tmpl_array.push(' <a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page ) %></a>');
+ tmpl_array.push(' </li>');
+ tmpl_array.push(' <% if ( ( show_page ) < page_count ) { %>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( show_page + 1 ) %>"><% print( show_page + 1 ) %></a></li>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page + 1 ) %></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' </ul>');
+ tmpl_array.push(' <span>');
+ tmpl_array.push(' showing <a data-toggle="tooltip" data-placement="top" title="Click to change the number of items on page" id="page_size_prompt"><%- items_shown %></a> of <%- total_items_count %> items');
+ tmpl_array.push(' </span>');
+
+ return _.template(tmpl_array.join(''));
+ },
});
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 client/galaxy/scripts/mvc/library/library-librarylist-view.js
--- a/client/galaxy/scripts/mvc/library/library-librarylist-view.js
+++ b/client/galaxy/scripts/mvc/library/library-librarylist-view.js
@@ -21,20 +21,19 @@
'click .sort-libraries-link' : 'sort_clicked'
},
- /**
- * Initialize and fetch the libraries from server.
- * Async render afterwards.
- * @param {object} options an options object
- */
defaults: {
page_count: null,
show_page: null
},
+ /**
+ * Initialize and fetch the libraries from server.
+ * Async render afterwards.
+ * @param {object} options an object with options
+ */
initialize : function( options ){
this.options = _.defaults( this.options || {}, this.defaults, options );
-
- var that = this;
+ var that = this;
this.modal = null;
// map of library model ids to library views = cache
this.rowViews = {};
@@ -61,19 +60,10 @@
*/
render: function ( options ) {
this.options = _.extend( this.options, options );
-
- if ( ( this.options.page_size != null ) && ( this.options.page_size == parseInt( this.options.page_size ) ) ) {
- Galaxy.libraries.preferences.set( { 'library_page_size': parseInt( this.options.page_size ) } );
- }
-
- $( ".tooltip" ).hide();
- // this.options.show_page = this.options.show_page || 1;
var template = this.templateLibraryList();
var libraries_to_render = null;
var models = null;
- if ( this.options.show_page === null || this.options.show_page < 1 ){
- this.options.show_page = 1;
- }
+ $( ".tooltip" ).hide();
if ( typeof options !== 'undefined' ){
models = typeof options.models !== 'undefined' ? options.models : null;
}
@@ -89,6 +79,10 @@
} else {
libraries_to_render = [];
}
+ // pagination
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
this.options.total_libraries_count = libraries_to_render.length
var page_start = ( Galaxy.libraries.preferences.get( 'library_page_size' ) * ( this.options.show_page - 1 ) );
this.options.page_count = Math.ceil( this.options.total_libraries_count / Galaxy.libraries.preferences.get( 'library_page_size' ) );
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 client/galaxy/scripts/mvc/tools/tools-tree.js
--- a/client/galaxy/scripts/mvc/tools/tools-tree.js
+++ b/client/galaxy/scripts/mvc/tools/tools-tree.js
@@ -126,7 +126,7 @@
// handle default value
if (!field.skip) {
if (input.optional && field.validate && !field.validate()) {
- value = 'None';
+ value = null;
}
add (job_input_id, input.id, value);
}
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/managers/folders.py
--- a/lib/galaxy/managers/folders.py
+++ b/lib/galaxy/managers/folders.py
@@ -16,14 +16,14 @@
Interface/service object for interacting with folders.
"""
- def get( self, trans, decoded_folder_id, check_ownership=False, check_accessible=True):
+ def get( self, trans, decoded_folder_id, check_manageable=False, check_accessible=True):
"""
Get the folder from the DB.
:param decoded_folder_id: decoded folder id
:type decoded_folder_id: int
- :param check_ownership: flag whether the check that user is owner
- :type check_ownership: bool
+ :param check_manageable: flag whether the check that user can manage item
+ :type check_manageable: bool
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
@@ -38,17 +38,17 @@
raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.' )
except Exception, e:
raise exceptions.InternalServerError( 'Error loading from the database.' + str( e ) )
- folder = self.secure( trans, folder, check_ownership, check_accessible )
+ folder = self.secure( trans, folder, check_manageable, check_accessible )
return folder
- def secure( self, trans, folder, check_ownership=True, check_accessible=True ):
+ def secure( self, trans, folder, check_manageable=True, check_accessible=True ):
"""
- Check if (a) user owns folder or (b) folder is accessible to user.
+ Check if (a) user can manage folder or (b) folder is accessible to user.
:param folder: folder item
:type folder: LibraryFolder
- :param check_ownership: flag whether the check that user is owner
- :type check_ownership: bool
+ :param check_manageable: flag whether to check that user can manage item
+ :type check_manageable: bool
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
@@ -58,23 +58,26 @@
# all folders are accessible to an admin
if trans.user_is_admin():
return folder
- if check_ownership:
- folder = self.check_ownership( trans, folder )
+ if check_manageable:
+ folder = self.check_manageable( trans, folder )
if check_accessible:
folder = self.check_accessible( trans, folder )
return folder
- def check_ownership( self, trans, folder ):
+ def check_manageable( self, trans, folder ):
"""
- Check whether the user is owner of the folder.
+ Check whether the user can manage the folder.
:returns: the original folder
:rtype: LibraryFolder
+
+ :raises: AuthenticationRequired, InsufficientPermissionsException
"""
if not trans.user:
- raise exceptions.AuthenticationRequired( "Must be logged in to manage Galaxy items", type='error' )
- if folder.user != trans.user:
- raise exceptions.ItemOwnershipException( "Folder is not owned by the current user", type='error' )
+ raise exceptions.AuthenticationRequired( "Must be logged in to manage Galaxy items.", type='error' )
+ current_user_roles = trans.get_current_user_roles()
+ if not trans.app.security_agent.can_manage_library_item( current_user_roles, folder ):
+ raise exceptions.InsufficientPermissionsException( "You don't have permissions to manage this folder.", type='error' )
else:
return folder
@@ -135,6 +138,22 @@
trans.app.security_agent.copy_library_permissions( trans, parent_folder, new_folder )
return new_folder
+ def delete( self, trans, folder, undelete=False ):
+ """
+ Mark given folder deleted/undeleted based on the flag.
+
+ :raises: ItemAccessibilityException
+ """
+ if not trans.user_is_admin():
+ folder = self.check_manageable( trans, folder )
+ if undelete:
+ folder.deleted = False
+ else:
+ folder.deleted = True
+ trans.sa_session.add( folder )
+ trans.sa_session.flush()
+ return folder
+
def get_current_roles( self, trans, folder ):
"""
Find all roles currently connected to relevant permissions
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2192,7 +2192,7 @@
return roles
class LibraryFolder( object, Dictifiable, HasName ):
- dict_element_visible_keys = ( 'id', 'parent_id', 'name', 'description', 'item_count', 'genome_build', 'update_time' )
+ dict_element_visible_keys = ( 'id', 'parent_id', 'name', 'description', 'item_count', 'genome_build', 'update_time', 'deleted' )
def __init__( self, name=None, description=None, item_count=0, order_id=None ):
self.name = name or "Unnamed folder"
self.description = description
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/tools/test.py
--- a/lib/galaxy/tools/test.py
+++ b/lib/galaxy/tools/test.py
@@ -196,12 +196,37 @@
if not isinstance(param_value, list):
param_value = [ param_value ]
processed_value = [ self.__add_uploaded_dataset( context.for_state(), v, param_extra, value ) for v in param_value ]
- if isinstance( value, basic.DataCollectionToolParameter ):
+ elif isinstance( value, basic.DataCollectionToolParameter ):
assert 'collection' in param_extra
collection_def = param_extra[ 'collection' ]
for ( name, value, extra ) in collection_def.collect_inputs():
require_file( name, value, extra, self.required_files )
processed_value = collection_def
+ elif isinstance( value, basic.SelectToolParameter ):
+ # Tests may specify values as either raw value or the value
+ # as they appear in the list - the API doesn't and shouldn't
+ # accept the text value - so we need to convert the text
+ # into the form value.
+ def process_param_value( param_value ):
+ found_value = False
+ value_for_text = None
+ if value.static_options:
+ for (text, opt_value, selected) in value.static_options:
+ if param_value == opt_value:
+ found_value = True
+ if value_for_text is None and param_value == text:
+ value_for_text = opt_value
+ if not found_value and value_for_text is not None:
+ processed_value = value_for_text
+ else:
+ processed_value = param_value
+ return processed_value
+ # Do replacement described above for lists or singleton
+ # values.
+ if isinstance( param_value, list ):
+ processed_value = map( process_param_value, param_value )
+ else:
+ processed_value = process_param_value( param_value )
else:
processed_value = param_value
expanded_inputs[ context.for_state() ] = processed_value
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/webapps/galaxy/api/folders.py
--- a/lib/galaxy/webapps/galaxy/api/folders.py
+++ b/lib/galaxy/webapps/galaxy/api/folders.py
@@ -44,7 +44,7 @@
:rtype: dict
"""
folder_id = self.folder_manager.cut_and_decode( trans, id )
- folder = self.folder_manager.get( trans, folder_id, check_ownership=False, check_accessible=True )
+ folder = self.folder_manager.get( trans, folder_id, check_manageable=False, check_accessible=True )
return_dict = self.folder_manager.get_folder_dict( trans, folder )
return return_dict
@@ -229,6 +229,32 @@
'Allowed values are: "set_permissions"' )
return self.folder_manager.get_current_roles( trans, folder )
+ @expose_api
+ def delete( self, trans, id, **kwd ):
+ """
+ delete( self, trans, id, **kwd )
+ * DELETE /api/folders/{id}
+ marks the folder with the given ``id`` as `deleted` (or removes the `deleted` mark if the `undelete` param is true)
+
+ .. note:: Currently, only admin users can un/delete folders.
+
+ :param id: the encoded id of the folder to un/delete
+ :type id: an encoded id string
+
+ :param undelete: (optional) flag specifying whether the item should be deleted or undeleted, defaults to false:
+ :type undelete: bool
+
+ :returns: detailed folder information
+ :rtype: dictionary
+
+ :raises: ItemAccessibilityException, MalformedId, ObjectNotFound
+ """
+ folder = self.folder_manager.get( trans, self.folder_manager.cut_and_decode( trans, id ), True )
+ undelete = util.string_as_bool( kwd.get( 'undelete', False ) )
+ folder = self.folder_manager.delete( trans, folder, undelete )
+ folder_dict = self.folder_manager.get_folder_dict( trans, folder )
+ return folder_dict
+
@web.expose_api
def update( self, trans, id, library_id, payload, **kwd ):
"""
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -932,11 +932,14 @@
@web.expose
def show_params( self, trans, dataset_id=None, from_noframe=None, **kwd ):
"""
- Show the parameters used for an HDA
+ Show the parameters used for the job associated with an HDA
"""
- hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
+ try:
+ hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( dataset_id ) )
+ except ValueError:
+ hda = None
if not hda:
- raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) )
+ raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % escape( str( dataset_id ) ) )
if not self._can_access_dataset( trans, hda ):
return trans.show_error_message( "You are not allowed to access this dataset" )
@@ -961,19 +964,30 @@
toolbox = self.get_toolbox()
tool = toolbox.get_tool( job.tool_id )
assert tool is not None, 'Requested tool has not been loaded.'
- #Load parameter objects, if a parameter type has changed, it's possible for the value to no longer be valid
+ # Load parameter objects, if a parameter type has changed, it's possible for the value to no longer be valid
try:
params_objects = job.get_param_values( trans.app, ignore_errors=False )
except:
params_objects = job.get_param_values( trans.app, ignore_errors=True )
- upgrade_messages = tool.check_and_update_param_values( job.get_param_values( trans.app, ignore_errors=True ), trans, update_values=False ) #use different param_objects here, since we want to display original values as much as possible
+ # use different param_objects in the following line, since we want to display original values as much as possible
+ upgrade_messages = tool.check_and_update_param_values( job.get_param_values( trans.app, ignore_errors=True ),
+ trans,
+ update_values=False )
has_parameter_errors = True
except:
pass
if job is None:
return trans.show_error_message( "Job information is not available for this dataset." )
- #TODO: we should provide the basic values along with the objects, in order to better handle reporting of old values during upgrade
- return trans.fill_template( "show_params.mako", inherit_chain=inherit_chain, history=trans.get_history(), hda=hda, job=job, tool=tool, params_objects=params_objects, upgrade_messages=upgrade_messages, has_parameter_errors=has_parameter_errors )
+ # TODO: we should provide the basic values along with the objects, in order to better handle reporting of old values during upgrade
+ return trans.fill_template( "show_params.mako",
+ inherit_chain=inherit_chain,
+ history=trans.get_history(),
+ hda=hda,
+ job=job,
+ tool=tool,
+ params_objects=params_objects,
+ upgrade_messages=upgrade_messages,
+ has_parameter_errors=has_parameter_errors )
@web.expose
def copy_datasets( self, trans, source_history=None, source_content_ids="", target_history_id=None, target_history_ids="", new_history_name="", do_copy=False, **kwd ):
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 lib/galaxy/webapps/galaxy/controllers/search.py
--- a/lib/galaxy/webapps/galaxy/controllers/search.py
+++ b/lib/galaxy/webapps/galaxy/controllers/search.py
@@ -1,4 +1,3 @@
-
"""
Contains a basic search interface for Galaxy
"""
@@ -8,7 +7,13 @@
log = logging.getLogger( __name__ )
+
class SearchController( BaseUIController ):
+
@web.expose
def index(self, trans):
- return trans.fill_template( "search/index.mako")
+ """
+ Per the message, this is not ready for human consumption, yet. Power
+ users can still use the search API.
+ """
+ return trans.show_message("Sorry, the search interface isn't quite ready for use, yet. Watch the release notes and check back later!")
diff -r 46a3d43d779fa7735029449935dad77474adf9b1 -r 719191cd0f3ea8ad2ff02ec303dabf0e22c31e60 static/scripts/galaxy.library.js
--- a/static/scripts/galaxy.library.js
+++ b/static/scripts/galaxy.library.js
@@ -36,7 +36,7 @@
initialize: function() {
this.routesHit = 0;
//keep count of number of routes handled by the application
- Backbone.history.on('route', function() { this.routesHit++; }, this);
+ Backbone.history.on( 'route', function() { this.routesHit++; }, this );
},
routes: {
@@ -45,6 +45,7 @@
"library/:library_id/permissions" : "library_permissions",
"folders/:folder_id/permissions" : "folder_permissions",
"folders/:id" : "folder_content",
+ "folders/:id/page/:show_page" : "folder_page",
"folders/:folder_id/datasets/:dataset_id" : "dataset_detail",
"folders/:folder_id/datasets/:dataset_id/permissions" : "dataset_permissions",
"folders/:folder_id/datasets/:dataset_id/versions/:ldda_id" : "dataset_version",
@@ -53,13 +54,13 @@
},
back: function() {
- if(this.routesHit > 1) {
+ if( this.routesHit > 1 ) {
//more than one route hit -> user did not land to current page directly
window.history.back();
} else {
//otherwise go to the home page. Use replaceState if available so
//the navigation doesn't create an extra history entry
- this.navigate('#', {trigger:true, replace:true});
+ this.navigate( '#', { trigger:true, replace:true } );
}
}
});
@@ -71,7 +72,8 @@
with_deleted : false,
sort_order : 'asc',
sort_by : 'name',
- library_page_size : 20
+ library_page_size : 20,
+ folder_page_size : 15
}
});
@@ -94,10 +96,10 @@
this.library_router = new LibraryRouter();
- this.library_router.on('route:libraries', function() {
- Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
- Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
- });
+ this.library_router.on( 'route:libraries', function() {
+ Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
+ Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
+ });
this.library_router.on('route:libraries_page', function( show_page ) {
if ( Galaxy.libraries.libraryToolbarView === null ){
@@ -108,66 +110,77 @@
}
});
- this.library_router.on('route:folder_content', function(id) {
+ this.library_router.on( 'route:folder_content', function( id ) {
if (Galaxy.libraries.folderToolbarView){
- Galaxy.libraries.folderToolbarView.$el.unbind('click');
- }
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: id});
- });
+ Galaxy.libraries.folderToolbarView.$el.unbind( 'click' );
+ }
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id } );
+ });
- this.library_router.on('route:download', function(folder_id, format) {
- if ($('#folder_list_body').find(':checked').length === 0) {
- mod_toastr.info( 'You must select at least one dataset to download' );
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: true, replace: true});
- } else {
- Galaxy.libraries.folderToolbarView.download(folder_id, format);
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: false, replace: true});
- }
- });
+ this.library_router.on( 'route:folder_page', function( id, show_page ) {
+ if ( Galaxy.libraries.folderToolbarView === null ){
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( {id: id} );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id, show_page: show_page } );
+ } else {
+ Galaxy.libraries.folderListView.render( { id: id, show_page: parseInt( show_page ) } )
+ }
+ });
- this.library_router.on('route:dataset_detail', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
- });
- this.library_router.on('route:dataset_version', function(folder_id, dataset_id, ldda_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
- });
+ this.library_router.on( 'route:download', function( folder_id, format ) {
+ if ( $( '#folder_list_body' ).find( ':checked' ).length === 0 ) {
+ mod_toastr.info( 'You must select at least one dataset to download' );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: true, replace: true } );
+ } else {
+ Galaxy.libraries.folderToolbarView.download( folder_id, format );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: false, replace: true } );
+ }
+ });
- this.library_router.on('route:dataset_permissions', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_detail', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
+ });
- this.library_router.on('route:library_permissions', function(library_id){
- if (Galaxy.libraries.libraryView){
- Galaxy.libraries.libraryView.$el.unbind('click');
- }
- Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_version', function(folder_id, dataset_id, ldda_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
+ });
- this.library_router.on('route:folder_permissions', function(folder_id){
- if (Galaxy.libraries.folderView){
- Galaxy.libraries.folderView.$el.unbind('click');
- }
- Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
- });
- this.library_router.on('route:import_datasets', function(folder_id, source){
- if (Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView){
- Galaxy.libraries.folderToolbarView.showImportModal({source:source});
- } else {
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: folder_id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: folder_id});
- Galaxy.libraries.folderToolbarView.showImportModal({source: source});
- }
- });
+ this.library_router.on( 'route:dataset_permissions', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:library_permissions', function(library_id){
+ if (Galaxy.libraries.libraryView){
+ Galaxy.libraries.libraryView.$el.unbind('click');
+ }
+ Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:folder_permissions', function(folder_id){
+ if (Galaxy.libraries.folderView){
+ Galaxy.libraries.folderView.$el.unbind('click');
+ }
+ Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:import_datasets', function( folder_id, source ){
+ if ( Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView ){
+ Galaxy.libraries.folderToolbarView.showImportModal( { source:source } );
+ } else {
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: folder_id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: folder_id } );
+ Galaxy.libraries.folderToolbarView.showImportModal( { source: source } );
+ }
+ });
Backbone.history.start({pushState: false});
}
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: ToolForm: Fix label for collections, set missing optional parameters to null
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/149784a152af/
Changeset: 149784a152af
Branch: next-stable
User: guerler
Date: 2014-12-05 22:35:46+00:00
Summary: ToolForm: Fix label for collections, set missing optional parameters to null
Affected #: 6 files
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 client/galaxy/scripts/mvc/tools/tools-select-content.js
--- a/client/galaxy/scripts/mvc/tools/tools-select-content.js
+++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js
@@ -86,7 +86,7 @@
// add collection selector
if (this.mode == 'single' || this.mode == 'collection') {
- radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
+ radio_buttons.push({icon: 'fa-folder-o', label : 'Dataset collection', value : 'collection' });
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
onchange : function() {
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 client/galaxy/scripts/mvc/tools/tools-tree.js
--- a/client/galaxy/scripts/mvc/tools/tools-tree.js
+++ b/client/galaxy/scripts/mvc/tools/tools-tree.js
@@ -126,7 +126,7 @@
// handle default value
if (!field.skip) {
if (input.optional && field.validate && !field.validate()) {
- value = 'None';
+ value = null;
}
add (job_input_id, input.id, value);
}
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 static/scripts/mvc/tools/tools-select-content.js
--- a/static/scripts/mvc/tools/tools-select-content.js
+++ b/static/scripts/mvc/tools/tools-select-content.js
@@ -86,7 +86,7 @@
// add collection selector
if (this.mode == 'single' || this.mode == 'collection') {
- radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
+ radio_buttons.push({icon: 'fa-folder-o', label : 'Dataset collection', value : 'collection' });
this.select_collection = new Ui.Select.View({
error_text : hdca_error,
onchange : function() {
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 static/scripts/mvc/tools/tools-tree.js
--- a/static/scripts/mvc/tools/tools-tree.js
+++ b/static/scripts/mvc/tools/tools-tree.js
@@ -126,7 +126,7 @@
// handle default value
if (!field.skip) {
if (input.optional && field.validate && !field.validate()) {
- value = 'None';
+ value = null;
}
add (job_input_id, input.id, value);
}
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 static/scripts/packed/mvc/tools/tools-select-content.js
--- a/static/scripts/packed/mvc/tools/tools-select-content.js
+++ b/static/scripts/packed/mvc/tools/tools-select-content.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement("<div/>");this.list={};var m=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=o.extensions.toString();if(j){j=j.replace(",",", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available.";if(j){h="No "+j+" dataset available."}var l="No dataset list available.";if(j){l="No "+j+" dataset list available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({error_text:l,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement("<div/>");this.list={};var m=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=o.extensions.toString();if(j){j=j.replace(",",", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available.";if(j){h="No "+j+" dataset available."}var l="No dataset list available.";if(j){l="No "+j+" dataset list available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",label:"Dataset collection",value:"collection"});this.select_collection=new e.Select.View({error_text:l,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
diff -r 20942ced453dc9f31b2d238855d1b8f5da3f078b -r 149784a152afc3d7164eaf7dfa7d5dc97be92671 static/scripts/packed/mvc/tools/tools-tree.js
--- a/static/scripts/packed/mvc/tools/tools-tree.js
+++ b/static/scripts/packed/mvc/tools/tools-tree.js
@@ -1,1 +1,1 @@
-define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(d){d=d||{};var a=this;this.job_def={};this.job_ids={};function c(g,f,e){a.job_def[g]=e;a.job_ids[g]=f}function b(l,o){for(var j in o){var g=o[j];if(g.input){var q=g.input;var k=l;if(l!=""){k+="|"}k+=q.name;switch(q.type){case"repeat":var f="section-";var t=[];var n=null;for(var s in g){var m=s.indexOf(f);if(m!=-1){m+=f.length;t.push(parseInt(s.substr(m)));if(!n){n=s.substr(0,m)}}}t.sort(function(u,i){return u-i});var j=0;for(var h in t){b(k+"_"+j++,g[n+t[h]])}break;case"conditional":var r=a.app.field_list[q.id].value();if(d[q.test_param.type]){r=d[q.test_param.type](r)}c(k+"|"+q.test_param.name,q.id,r);var e=a.matchCase(q,r);if(e!=-1){b(k,o[q.id+"-section-"+e])}break;default:var p=a.app.field_list[q.id];var r=p.value();if(d[q.type]){r=d[q.type](r)}if(!p.skip){if(q.optional&&p.validate&&!p.validate()){r="None"}c(k,q.id,r)}}}}}b("",this.dict);return this.job_def},match:function(a){return this.job_ids&&this.job_ids[a]},matchCase:function(a,c){if(a.test_param.type=="boolean"){if(c=="true"){c=a.test_param.truevalue||"true"}else{c=a.test_param.falsevalue||"false"}}for(var b in a.cases){if(a.cases[b].value==c){return b}}return -1},matchModel:function(c,e){var a={};var b=this;function d(f,o){for(var l in o){var h=o[l];var m=h.name;if(f!=""){m=f+"|"+m}switch(h.type){case"repeat":for(var k in h.cache){d(m+"_"+k,h.cache[k])}break;case"conditional":var p=h.test_param&&h.test_param.value;var g=b.matchCase(h,p);if(g!=-1){d(m,h.cases[g].inputs)}break;default:var n=b.app.tree.job_ids[m];if(n){e(n,h)}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(k,h){if(typeof h==="string"){var f=b.app.tree.job_ids[k];if(f){a[f]=h}}else{for(var g in h){var e=g;if(k!==""){var j="|";if(h instanceof Array){j="_"}e=k+j+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})});
\ No newline at end of file
+define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){this.dict={};this.xml=$("<div/>");if(!this.app.section){return{}}this._iterate(this.app.section.$el,this.dict,this.xml)},finalize:function(d){d=d||{};var a=this;this.job_def={};this.job_ids={};function c(g,f,e){a.job_def[g]=e;a.job_ids[g]=f}function b(l,o){for(var j in o){var g=o[j];if(g.input){var q=g.input;var k=l;if(l!=""){k+="|"}k+=q.name;switch(q.type){case"repeat":var f="section-";var t=[];var n=null;for(var s in g){var m=s.indexOf(f);if(m!=-1){m+=f.length;t.push(parseInt(s.substr(m)));if(!n){n=s.substr(0,m)}}}t.sort(function(u,i){return u-i});var j=0;for(var h in t){b(k+"_"+j++,g[n+t[h]])}break;case"conditional":var r=a.app.field_list[q.id].value();if(d[q.test_param.type]){r=d[q.test_param.type](r)}c(k+"|"+q.test_param.name,q.id,r);var e=a.matchCase(q,r);if(e!=-1){b(k,o[q.id+"-section-"+e])}break;default:var p=a.app.field_list[q.id];var r=p.value();if(d[q.type]){r=d[q.type](r)}if(!p.skip){if(q.optional&&p.validate&&!p.validate()){r=null}c(k,q.id,r)}}}}}b("",this.dict);return this.job_def},match:function(a){return this.job_ids&&this.job_ids[a]},matchCase:function(a,c){if(a.test_param.type=="boolean"){if(c=="true"){c=a.test_param.truevalue||"true"}else{c=a.test_param.falsevalue||"false"}}for(var b in a.cases){if(a.cases[b].value==c){return b}}return -1},matchModel:function(c,e){var a={};var b=this;function d(f,o){for(var l in o){var h=o[l];var m=h.name;if(f!=""){m=f+"|"+m}switch(h.type){case"repeat":for(var k in h.cache){d(m+"_"+k,h.cache[k])}break;case"conditional":var p=h.test_param&&h.test_param.value;var g=b.matchCase(h,p);if(g!=-1){d(m,h.cases[g].inputs)}break;default:var n=b.app.tree.job_ids[m];if(n){e(n,h)}}}}d("",c.inputs);return a},matchResponse:function(c){var a={};var b=this;function d(k,h){if(typeof h==="string"){var f=b.app.tree.job_ids[k];if(f){a[f]=h}}else{for(var g in h){var e=g;if(k!==""){var j="|";if(h instanceof Array){j="_"}e=k+j+e}d(e,h[g])}}}d("",c);return a},references:function(c,e){var g=[];var b=this;function d(h,j){var i=$(j).children();var l=[];var k=false;i.each(function(){var o=this;var n=$(o).attr("id");if(n!==c){var m=b.app.input_list[n];if(m){if(m.name==h){k=true;return false}if(m.data_ref==h&&m.type==e){l.push(n)}}}});if(!k){g=g.concat(l);i.each(function(){d(h,this)})}}var f=this.xml.find("#"+c);if(f.length>0){var a=this.app.input_list[c];if(a){d(a.name,f.parent())}}return g},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("section-row")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})}})});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: paginate library folder contents to prevent loooooong rendering when hundreds of items are in one folder
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/20942ced453d/
Changeset: 20942ced453d
Branch: next-stable
User: martenson
Date: 2014-12-05 22:21:57+00:00
Summary: paginate library folder contents to prevent loooooong rendering when hundreds of items are in one folder
Affected #: 12 files
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b client/galaxy/scripts/galaxy.library.js
--- a/client/galaxy/scripts/galaxy.library.js
+++ b/client/galaxy/scripts/galaxy.library.js
@@ -36,7 +36,7 @@
initialize: function() {
this.routesHit = 0;
//keep count of number of routes handled by the application
- Backbone.history.on('route', function() { this.routesHit++; }, this);
+ Backbone.history.on( 'route', function() { this.routesHit++; }, this );
},
routes: {
@@ -45,6 +45,7 @@
"library/:library_id/permissions" : "library_permissions",
"folders/:folder_id/permissions" : "folder_permissions",
"folders/:id" : "folder_content",
+ "folders/:id/page/:show_page" : "folder_page",
"folders/:folder_id/datasets/:dataset_id" : "dataset_detail",
"folders/:folder_id/datasets/:dataset_id/permissions" : "dataset_permissions",
"folders/:folder_id/datasets/:dataset_id/versions/:ldda_id" : "dataset_version",
@@ -53,13 +54,13 @@
},
back: function() {
- if(this.routesHit > 1) {
+ if( this.routesHit > 1 ) {
//more than one route hit -> user did not land to current page directly
window.history.back();
} else {
//otherwise go to the home page. Use replaceState if available so
//the navigation doesn't create an extra history entry
- this.navigate('#', {trigger:true, replace:true});
+ this.navigate( '#', { trigger:true, replace:true } );
}
}
});
@@ -71,7 +72,8 @@
with_deleted : false,
sort_order : 'asc',
sort_by : 'name',
- library_page_size : 20
+ library_page_size : 20,
+ folder_page_size : 15
}
});
@@ -94,10 +96,10 @@
this.library_router = new LibraryRouter();
- this.library_router.on('route:libraries', function() {
- Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
- Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
- });
+ this.library_router.on( 'route:libraries', function() {
+ Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
+ Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
+ });
this.library_router.on('route:libraries_page', function( show_page ) {
if ( Galaxy.libraries.libraryToolbarView === null ){
@@ -108,66 +110,77 @@
}
});
- this.library_router.on('route:folder_content', function(id) {
+ this.library_router.on( 'route:folder_content', function( id ) {
if (Galaxy.libraries.folderToolbarView){
- Galaxy.libraries.folderToolbarView.$el.unbind('click');
- }
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: id});
- });
+ Galaxy.libraries.folderToolbarView.$el.unbind( 'click' );
+ }
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id } );
+ });
- this.library_router.on('route:download', function(folder_id, format) {
- if ($('#folder_list_body').find(':checked').length === 0) {
- mod_toastr.info( 'You must select at least one dataset to download' );
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: true, replace: true});
- } else {
- Galaxy.libraries.folderToolbarView.download(folder_id, format);
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: false, replace: true});
- }
- });
+ this.library_router.on( 'route:folder_page', function( id, show_page ) {
+ if ( Galaxy.libraries.folderToolbarView === null ){
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( {id: id} );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id, show_page: show_page } );
+ } else {
+ Galaxy.libraries.folderListView.render( { id: id, show_page: parseInt( show_page ) } )
+ }
+ });
- this.library_router.on('route:dataset_detail', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
- });
- this.library_router.on('route:dataset_version', function(folder_id, dataset_id, ldda_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
- });
+ this.library_router.on( 'route:download', function( folder_id, format ) {
+ if ( $( '#folder_list_body' ).find( ':checked' ).length === 0 ) {
+ mod_toastr.info( 'You must select at least one dataset to download' );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: true, replace: true } );
+ } else {
+ Galaxy.libraries.folderToolbarView.download( folder_id, format );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: false, replace: true } );
+ }
+ });
- this.library_router.on('route:dataset_permissions', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_detail', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
+ });
- this.library_router.on('route:library_permissions', function(library_id){
- if (Galaxy.libraries.libraryView){
- Galaxy.libraries.libraryView.$el.unbind('click');
- }
- Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_version', function(folder_id, dataset_id, ldda_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
+ });
- this.library_router.on('route:folder_permissions', function(folder_id){
- if (Galaxy.libraries.folderView){
- Galaxy.libraries.folderView.$el.unbind('click');
- }
- Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
- });
- this.library_router.on('route:import_datasets', function(folder_id, source){
- if (Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView){
- Galaxy.libraries.folderToolbarView.showImportModal({source:source});
- } else {
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: folder_id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: folder_id});
- Galaxy.libraries.folderToolbarView.showImportModal({source: source});
- }
- });
+ this.library_router.on( 'route:dataset_permissions', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:library_permissions', function(library_id){
+ if (Galaxy.libraries.libraryView){
+ Galaxy.libraries.libraryView.$el.unbind('click');
+ }
+ Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:folder_permissions', function(folder_id){
+ if (Galaxy.libraries.folderView){
+ Galaxy.libraries.folderView.$el.unbind('click');
+ }
+ Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:import_datasets', function( folder_id, source ){
+ if ( Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView ){
+ Galaxy.libraries.folderToolbarView.showImportModal( { source:source } );
+ } else {
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: folder_id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: folder_id } );
+ Galaxy.libraries.folderToolbarView.showImportModal( { source: source } );
+ }
+ });
Backbone.history.start({pushState: false});
}
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b client/galaxy/scripts/mvc/library/library-folderlist-view.js
--- a/client/galaxy/scripts/mvc/library/library-folderlist-view.js
+++ b/client/galaxy/scripts/mvc/library/library-folderlist-view.js
@@ -15,322 +15,359 @@
) {
var FolderListView = Backbone.View.extend({
- el : '#folder_items_element',
- defaults: {
- 'include_deleted' : false
- },
- // progress percentage
- progress: 0,
- // progress rate per one item
- progressStep: 1,
- // self modal
- modal : null,
+ el : '#folder_items_element',
+ // progress percentage
+ progress: 0,
+ // progress rate per one item
+ progressStep: 1,
- folderContainer: null,
+ folderContainer: null,
- sort: 'asc',
+ sort: 'asc',
- events: {
- 'click #select-all-checkboxes' : 'selectAll',
- 'click .dataset_row' : 'selectClickedRow',
- 'click .sort-folder-link' : 'sortColumnClicked'
- },
+ events: {
+ 'click #select-all-checkboxes' : 'selectAll',
+ 'click .dataset_row' : 'selectClickedRow',
+ 'click .sort-folder-link' : 'sortColumnClicked'
+ },
- // cache of rendered views
- rowViews: {},
-
- initialize : function(options){
- this.options = _.defaults(this.options || {}, options);
- this.fetchFolder();
- },
+ collection: null,
- fetchFolder: function(options){
- var options = options || {};
- this.options.include_deleted = options.include_deleted;
- var that = this;
+ defaults: {
+ include_deleted: false,
+ page_count: null,
+ show_page: null
+ },
- this.collection = new mod_library_model.Folder();
+ /**
+ * Initialize and fetch the folder from the server.
+ * @param {object} options an object with options
+ */
+ initialize : function( options ){
+ this.options = _.defaults( this.options || {}, this.defaults, options );
+ this.modal = null;
+ // map of folder item ids to item views = cache
+ this.rowViews = {};
- // start to listen if someone modifies collection
- this.listenTo(this.collection, 'add', this.renderOne);
- this.listenTo(this.collection, 'remove', this.removeOne);
+ // create a collection of folder items for this view
+ this.collection = new mod_library_model.Folder();
- this.folderContainer = new mod_library_model.FolderContainer({id: this.options.id});
- this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
- if (this.options.include_deleted){
- this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
- }
- this.folderContainer.fetch({
- success: function(folder_container) {
- that.folder_container = folder_container;
- that.render();
- that.addAll(folder_container.get('folder').models);
- if (that.options.dataset_id){
- row = _.findWhere(that.rowViews, {id: that.options.dataset_id});
- if (row) {
+ // start to listen if someone modifies the collection
+ this.listenTo( this.collection, 'add', this.renderOne );
+ this.listenTo( this.collection, 'remove', this.removeOne );
+
+ this.fetchFolder();
+ },
+
+ fetchFolder: function( options ){
+ var options = options || {};
+ this.options.include_deleted = options.include_deleted;
+ var that = this;
+
+ this.folderContainer = new mod_library_model.FolderContainer( { id: this.options.id } );
+ this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
+
+ if ( this.options.include_deleted ){
+ this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
+ }
+ this.folderContainer.fetch({
+ success: function( folder_container ) {
+ that.folder_container = folder_container;
+ that.render();
+ },
+ error: function( model, response ){
+ if ( typeof response.responseJSON !== "undefined" ){
+ mod_toastr.error( response.responseJSON.err_msg + ' Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ } else {
+ mod_toastr.error( 'An error ocurred. Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ }
+ }
+ });
+ },
+
+ render: function ( options ){
+ this.options = _.extend( this.options, options );
+ var template = this.templateFolder();
+ $(".tooltip").hide();
+
+ // find the upper id in the full path
+ var path = this.folderContainer.attributes.metadata.full_path;
+ var upper_folder_id;
+ if ( path.length === 1 ){ // the library is above us
+ upper_folder_id = 0;
+ } else {
+ upper_folder_id = path[ path.length-2 ][ 0 ];
+ }
+
+ this.$el.html( template( {
+ path: this.folderContainer.attributes.metadata.full_path,
+ parent_library_id: this.folderContainer.attributes.metadata.parent_library_id,
+ id: this.options.id,
+ upper_folder_id: upper_folder_id,
+ order: this.sort
+ } ) );
+
+ // when dataset_id is present render its details too
+ if ( this.options.dataset_id ){
+ row = _.findWhere( that.rowViews, { id: this.options.dataset_id } );
+ if ( row ) {
row.showDatasetDetails();
} else {
- mod_toastr.error('Dataset not found. Showing folder instead.');
+ mod_toastr.error( 'Requested dataset not found. Showing folder instead.' );
}
+ } else {
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.paginate();
+ }
+ $("#center [data-toggle]").tooltip();
+ $("#center").css('overflow','auto');
+ },
+
+ paginate: function( options ){
+ this.options = _.extend( this.options, options );
+
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.options.total_items_count = this.folder_container.get( 'folder' ).models.length;
+ this.options.page_count = Math.ceil( this.options.total_items_count / Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ var page_start = ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * ( this.options.show_page - 1 ) );
+ var items_to_render = null;
+ items_to_render = this.folder_container.get( 'folder' ).models.slice( page_start, page_start + Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ this.options.items_shown = items_to_render.length;
+ // User requests page with no items
+ if ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * this.options.show_page > ( this.options.total_items_count + Galaxy.libraries.preferences.get( 'folder_page_size' ) ) ){
+ items_to_render = [];
+ }
+ Galaxy.libraries.folderToolbarView.renderPaginator( this.options );
+ this.collection.reset();
+ this.addAll( items_to_render )
+ },
+
+ /**
+ * Adds all given models to the collection.
+ * @param {array of Item or FolderAsModel} array of models that should
+ * be added to the view's collection.
+ */
+ addAll: function( models ){
+ _.each(models, function( model ) {
+ Galaxy.libraries.folderListView.collection.add( model );
+ });
+ $( "#center [data-toggle]" ).tooltip();
+ this.checkEmptiness();
+ this.postRender();
+ },
+
+ /**
+ * Call this after all models are added to the collection
+ * to ensure that the folder toolbar will show proper options
+ * and that event will be bound on all subviews.
+ */
+ postRender: function(){
+ var fetched_metadata = this.folderContainer.attributes.metadata;
+ fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
+ Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * Iterates this view's collection and calls the render
+ * function for each. Also binds the hover behavior.
+ */
+ renderAll: function(){
+ var that = this;
+ _.each( this.collection.models.reverse(), function( model ) {
+ that.renderOne( model );
+ });
+ this.postRender();
+ },
+
+ /**
+ * Creates a view for the given model and adds it to the folder view.
+ * @param {Item or FolderAsModel} model of the view that will be rendered
+ */
+ renderOne: function(model){
+ if (model.get('type') !== 'folder'){
+ this.options.contains_file = true;
+ // model.set('readable_size', this.size_to_string(model.get('file_size')));
}
- },
- error: function(model, response){
- if (typeof response.responseJSON !== "undefined"){
- mod_toastr.error(response.responseJSON.err_msg + ' Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- } else {
- mod_toastr.error('An error ocurred. Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- }
+ model.set('folder_id', this.id);
+ var rowView = new mod_library_folderrow_view.FolderRowView(model);
+
+ // save new rowView to cache
+ this.rowViews[model.get('id')] = rowView;
+
+ this.$el.find('#first_folder_item').after(rowView.el);
+
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * removes the view of the given model from the DOM
+ * @param {Item or FolderAsModel} model of the view that will be removed
+ */
+ removeOne: function( model ){
+ this.$el.find( '#' + model.id ).remove();
+ },
+
+ /** Checks whether the list is empty and adds/removes the message */
+ checkEmptiness : function(){
+ if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
+ this.$el.find('.empty-folder-message').show();
+ } else {
+ this.$el.find('.empty-folder-message').hide();
}
- });
- },
+ },
- render: function (options) {
- this.options = _.defaults(this.options, options);
- var template = this.templateFolder();
- $(".tooltip").hide();
+ /** User clicked the table heading = he wants to sort stuff */
+ sortColumnClicked : function(event){
+ event.preventDefault();
+ if (this.sort === 'asc'){
+ this.sortFolder('name','desc');
+ this.sort = 'desc';
+ } else {
+ this.sortFolder('name','asc');
+ this.sort = 'asc';
+ }
+ this.render();
+ this.renderAll();
+ this.checkEmptiness();
+ },
- // TODO move to server
- // find the upper id in the full path
- var path = this.folderContainer.attributes.metadata.full_path;
- var upper_folder_id;
- if (path.length === 1){ // the library is above us
- upper_folder_id = 0;
- } else {
- upper_folder_id = path[path.length-2][0];
+ /**
+ * Sorts the underlying collection according to the parameters received.
+ * Currently supports only sorting by name.
+ */
+ sortFolder: function(sort_by, order){
+ if (sort_by === 'name'){
+ if (order === 'asc'){
+ return this.collection.sortByNameAsc();
+ } else if (order === 'desc'){
+ return this.collection.sortByNameDesc();
+ }
+ }
+ },
+
+ /**
+ * User clicked the checkbox in the table heading
+ * @param {context} event
+ */
+ selectAll : function (event) {
+ var selected = event.target.checked;
+ that = this;
+ // Iterate each checkbox
+ $(':checkbox', '#folder_list_body').each(function() {
+ this.checked = selected;
+ $row = $(this.parentElement.parentElement);
+ // Change color of selected/unselected
+ if (selected) {
+ that.makeDarkRow($row);
+ } else {
+ that.makeWhiteRow($row);
+ }
+ });
+ },
+
+ /**
+ * Check checkbox if user clicks on the whole row or
+ * on the checkbox itself
+ */
+ selectClickedRow : function (event) {
+ var checkbox = '';
+ var $row;
+ var source;
+ if (event.target.localName === 'input'){
+ checkbox = event.target;
+ $row = $(event.target.parentElement.parentElement);
+ source = 'input';
+ } else if (event.target.localName === 'td') {
+ checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
+ $row = $(event.target.parentElement);
+ source = 'td';
+ }
+ if (checkbox.checked){
+ if (source==='td'){
+ checkbox.checked = '';
+ this.makeWhiteRow($row);
+ } else if (source==='input') {
+ this.makeDarkRow($row);
+ }
+ } else {
+ if (source==='td'){
+ checkbox.checked = 'selected';
+ this.makeDarkRow($row);
+ } else if (source==='input') {
+ this.makeWhiteRow($row);
+ }
+ }
+ },
+
+ makeDarkRow: function($row){
+ $row.removeClass('light').addClass('dark');
+ $row.find('a').removeClass('light').addClass('dark');
+ $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
+ },
+
+ makeWhiteRow: function($row){
+ $row.removeClass('dark').addClass('light');
+ $row.find('a').removeClass('dark').addClass('light');
+ $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
+ },
+
+ templateFolder : function (){
+ var tmpl_array = [];
+
+ // BREADCRUMBS
+ tmpl_array.push('<ol class="breadcrumb">');
+ tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
+ tmpl_array.push(' <% _.each(path, function(path_item) { %>');
+ tmpl_array.push(' <% if (path_item[0] != id) { %>');
+ tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
+ tmpl_array.push( '<% } else { %>');
+ tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</ol>');
+
+ // FOLDER CONTENT
+ tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
+ tmpl_array.push(' <thead>');
+ tmpl_array.push(' <th class="button_heading"></th>');
+ tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
+ tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
+ tmpl_array.push(' <th style="width:5%;">data type</th>');
+ tmpl_array.push(' <th style="width:10%;">size</th>');
+ tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
+ tmpl_array.push(' <th style="width:10%;"></th> ');
+ tmpl_array.push(' </thead>');
+ tmpl_array.push(' <tbody id="folder_list_body">');
+ tmpl_array.push(' <tr id="first_folder_item">');
+ tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' </tr>');
+
+ tmpl_array.push(' </tbody>');
+ tmpl_array.push('</table>');
+ tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
+
+ return _.template(tmpl_array.join(''));
}
-
- this.$el.html(template({ path: this.folderContainer.attributes.metadata.full_path, parent_library_id: this.folderContainer.attributes.metadata.parent_library_id, id: this.options.id, upper_folder_id: upper_folder_id, order: this.sort}));
-
- // initialize the library tooltips
- $("#center [data-toggle]").tooltip();
- //hack to show scrollbars
- $("#center").css('overflow','auto');
- },
-
- /**
- * Call this after all models are added to the collection
- * to ensure that the folder toolbar will show proper options
- * and that event will be bound on all subviews.
- */
- postRender: function(){
- var fetched_metadata = this.folderContainer.attributes.metadata;
- fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
- Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * Adds all given models to the collection.
- * @param {array of Item or FolderAsModel} array of models that should
- * be added to the view's collection.
- */
- addAll: function(models){
- _.each(models.reverse(), function(model) {
- Galaxy.libraries.folderListView.collection.add(model);
- });
-
- $("#center [data-toggle]").tooltip();
- this.checkEmptiness();
-
- this.postRender();
- },
-
- /**
- * Iterates this view's collection and calls the render
- * function for each. Also binds the hover behavior.
- */
- renderAll: function(){
- var that = this;
- _.each(this.collection.models.reverse(), function(model) {
- that.renderOne(model);
- });
- this.postRender();
- },
-
- /**
- * Creates a view for the given model and adds it to the folder view.
- * @param {Item or FolderAsModel} model of the view that will be rendered
- */
- renderOne: function(model){
- if (model.get('type') !== 'folder'){
- this.options.contains_file = true;
- // model.set('readable_size', this.size_to_string(model.get('file_size')));
- }
- model.set('folder_id', this.id);
- var rowView = new mod_library_folderrow_view.FolderRowView(model);
-
- // save new rowView to cache
- this.rowViews[model.get('id')] = rowView;
-
- this.$el.find('#first_folder_item').after(rowView.el);
-
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * removes the view of the given model from the DOM
- * @param {Item or FolderAsModel} model of the view that will be removed
- */
- removeOne: function(model){
- this.$el.find('#' + model.id).remove();
- },
-
- /** Checks whether the list is empty and adds/removes the message */
- checkEmptiness : function(){
- if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
- this.$el.find('.empty-folder-message').show();
- } else {
- this.$el.find('.empty-folder-message').hide();
- }
- },
-
- /** User clicked the table heading = he wants to sort stuff */
- sortColumnClicked : function(event){
- event.preventDefault();
- if (this.sort === 'asc'){
- this.sortFolder('name','desc');
- this.sort = 'desc';
- } else {
- this.sortFolder('name','asc');
- this.sort = 'asc';
- }
- this.render();
- this.renderAll();
- this.checkEmptiness();
- },
-
- /**
- * Sorts the underlying collection according to the parameters received.
- * Currently supports only sorting by name.
- */
- sortFolder: function(sort_by, order){
- if (sort_by === 'name'){
- if (order === 'asc'){
- return this.collection.sortByNameAsc();
- } else if (order === 'desc'){
- return this.collection.sortByNameDesc();
- }
- }
- },
-
- /**
- * User clicked the checkbox in the table heading
- * @param {context} event
- */
- selectAll : function (event) {
- var selected = event.target.checked;
- that = this;
- // Iterate each checkbox
- $(':checkbox', '#folder_list_body').each(function() {
- this.checked = selected;
- $row = $(this.parentElement.parentElement);
- // Change color of selected/unselected
- if (selected) {
- that.makeDarkRow($row);
- } else {
- that.makeWhiteRow($row);
- }
- });
- },
-
- /**
- * Check checkbox if user clicks on the whole row or
- * on the checkbox itself
- */
- selectClickedRow : function (event) {
- var checkbox = '';
- var $row;
- var source;
- if (event.target.localName === 'input'){
- checkbox = event.target;
- $row = $(event.target.parentElement.parentElement);
- source = 'input';
- } else if (event.target.localName === 'td') {
- checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
- $row = $(event.target.parentElement);
- source = 'td';
- }
- if (checkbox.checked){
- if (source==='td'){
- checkbox.checked = '';
- this.makeWhiteRow($row);
- } else if (source==='input') {
- this.makeDarkRow($row);
- }
- } else {
- if (source==='td'){
- checkbox.checked = 'selected';
- this.makeDarkRow($row);
- } else if (source==='input') {
- this.makeWhiteRow($row);
- }
- }
- },
-
- makeDarkRow: function($row){
- $row.removeClass('light').addClass('dark');
- $row.find('a').removeClass('light').addClass('dark');
- $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
- },
-
- makeWhiteRow: function($row){
- $row.removeClass('dark').addClass('light');
- $row.find('a').removeClass('dark').addClass('light');
- $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
- },
-
- templateFolder : function (){
- var tmpl_array = [];
-
- // BREADCRUMBS
- tmpl_array.push('<ol class="breadcrumb">');
- tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
- tmpl_array.push(' <% _.each(path, function(path_item) { %>');
- tmpl_array.push(' <% if (path_item[0] != id) { %>');
- tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
- tmpl_array.push( '<% } else { %>');
- tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</ol>');
-
- // FOLDER CONTENT
- tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
- tmpl_array.push(' <thead>');
- tmpl_array.push(' <th class="button_heading"></th>');
- tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
- tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
- tmpl_array.push(' <th style="width:5%;">data type</th>');
- tmpl_array.push(' <th style="width:10%;">size</th>');
- tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
- tmpl_array.push(' <th style="width:10%;"></th> ');
- tmpl_array.push(' </thead>');
- tmpl_array.push(' <tbody id="folder_list_body">');
- tmpl_array.push(' <tr id="first_folder_item">');
- tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' </tr>');
-
- tmpl_array.push(' </tbody>');
- tmpl_array.push('</table>');
- tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
-
- return _.template(tmpl_array.join(''));
- }
-
+
});
return {
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
--- a/client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
+++ b/client/galaxy/scripts/mvc/library/library-foldertoolbar-view.js
@@ -20,7 +20,9 @@
'click #toolbtn_bulk_import' : 'modalBulkImport',
'click #include_deleted_datasets_chk' : 'checkIncludeDeleted',
'click #toolbtn_show_libinfo' : 'showLibInfo',
- 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets'
+ 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets',
+ 'click #page_size_prompt' : 'showPageSizePrompt'
+
},
defaults: {
@@ -90,6 +92,22 @@
this.$el.html(toolbar_template(template_defaults));
},
+ /**
+ * Called from FolderListView when needed.
+ * @param {object} options common options
+ */
+ renderPaginator: function( options ){
+ this.options = _.extend( this.options, options );
+ var paginator_template = this.templatePaginator();
+ this.$el.find( '#folder_paginator' ).html( paginator_template({
+ id: this.options.id,
+ show_page: parseInt( this.options.show_page ),
+ page_count: parseInt( this.options.page_count ),
+ total_items_count: this.options.total_items_count,
+ items_shown: this.options.items_shown
+ }));
+ },
+
configureElements: function(options){
this.options = _.extend(this.options, options);
@@ -833,11 +851,11 @@
var popped_item = lddas_set.pop();
if ( typeof popped_item === "undefined" ) {
if ( this.options.chain_call_control.failed_number === 0 ){
- mod_toastr.success( 'Selected datasets deleted' );
+ mod_toastr.success( 'Selected datasets were deleted.' );
} else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
- mod_toastr.error( 'There was an error and no datasets were deleted.' );
+ mod_toastr.error( 'There was an error and no datasets were deleted. Please make sure you have sufficient permissions.' );
} else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
- mod_toastr.warning( 'Some of the datasets could not be deleted' );
+ mod_toastr.warning( 'Some of the datasets could not be deleted. Please make sure you have sufficient permissions.' );
}
Galaxy.modal.hide();
return this.deleted_lddas;
@@ -976,6 +994,14 @@
}
},
+ showPageSizePrompt: function(){
+ var folder_page_size = prompt( 'How many items per page do you want to see?', Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ if ( ( folder_page_size != null ) && ( folder_page_size == parseInt( folder_page_size ) ) ) {
+ Galaxy.libraries.preferences.set( { 'folder_page_size': parseInt( folder_page_size ) } );
+ Galaxy.libraries.folderListView.render( { id: this.options.id, show_page: 1 } );
+ }
+ },
+
templateToolBar: function(){
tmpl_array = [];
@@ -1016,7 +1042,6 @@
tmpl_array.push(' <button style="display:none;" data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button add-library-items" type="button"><span class="fa fa-plus"></span><span class="fa fa-file"></span></span></button>');
tmpl_array.push('<% } %>');
-
tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button dataset-manipulation" style="margin-left: 0.5em; display:none;" type="button"><span class="fa fa-book"></span> to History</button>');
tmpl_array.push(' <div id="toolbtn_dl" class="btn-group dataset-manipulation" style="margin-left: 0.5em; display:none; ">');
tmpl_array.push(' <button title="Download selected datasets as archive" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
@@ -1032,6 +1057,10 @@
tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show library information" id="toolbtn_show_libinfo" class="primary-button" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Library Info</button>');
tmpl_array.push(' <span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki"><a href="https://wiki.galaxyproject.org/DataLibraries/screen/FolderContents" target="_blank"><button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button></a></span>');
+ tmpl_array.push(' <span id="folder_paginator" class="library-paginator">');
+ // paginator will append here
+ tmpl_array.push(' </span>');
+
tmpl_array.push(' </div>');
// TOOLBAR END
tmpl_array.push(' <div id="folder_items_element">');
@@ -1239,7 +1268,41 @@
tmpl_array.push('</ul>');
return _.template(tmpl_array.join(''));
- }
+ },
+
+ templatePaginator: function(){
+ tmpl_array = [];
+
+ tmpl_array.push(' <ul class="pagination pagination-sm">');
+ tmpl_array.push(' <% if ( ( show_page - 1 ) > 0 ) { %>');
+ tmpl_array.push(' <% if ( ( show_page - 1 ) > page_count ) { %>'); // we are on higher page than total page count
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( show_page - 1 ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% } else { %>'); // we are on the first page
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/1"><span class="fa fa-angle-double-left"></span></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <li class="active">');
+ tmpl_array.push(' <a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page ) %></a>');
+ tmpl_array.push(' </li>');
+ tmpl_array.push(' <% if ( ( show_page ) < page_count ) { %>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( show_page + 1 ) %>"><% print( show_page + 1 ) %></a></li>');
+ tmpl_array.push(' <li><a href="#folders/<%= id %>/page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>');
+ tmpl_array.push(' <% } else { %>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( show_page ) %>"><% print( show_page + 1 ) %></a></li>');
+ tmpl_array.push(' <li class="disabled"><a href="#folders/<%= id %>/page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' </ul>');
+ tmpl_array.push(' <span>');
+ tmpl_array.push(' showing <a data-toggle="tooltip" data-placement="top" title="Click to change the number of items on page" id="page_size_prompt"><%- items_shown %></a> of <%- total_items_count %> items');
+ tmpl_array.push(' </span>');
+
+ return _.template(tmpl_array.join(''));
+ },
});
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b client/galaxy/scripts/mvc/library/library-librarylist-view.js
--- a/client/galaxy/scripts/mvc/library/library-librarylist-view.js
+++ b/client/galaxy/scripts/mvc/library/library-librarylist-view.js
@@ -21,20 +21,19 @@
'click .sort-libraries-link' : 'sort_clicked'
},
- /**
- * Initialize and fetch the libraries from server.
- * Async render afterwards.
- * @param {object} options an options object
- */
defaults: {
page_count: null,
show_page: null
},
+ /**
+ * Initialize and fetch the libraries from server.
+ * Async render afterwards.
+ * @param {object} options an object with options
+ */
initialize : function( options ){
this.options = _.defaults( this.options || {}, this.defaults, options );
-
- var that = this;
+ var that = this;
this.modal = null;
// map of library model ids to library views = cache
this.rowViews = {};
@@ -61,19 +60,10 @@
*/
render: function ( options ) {
this.options = _.extend( this.options, options );
-
- if ( ( this.options.page_size != null ) && ( this.options.page_size == parseInt( this.options.page_size ) ) ) {
- Galaxy.libraries.preferences.set( { 'library_page_size': parseInt( this.options.page_size ) } );
- }
-
- $( ".tooltip" ).hide();
- // this.options.show_page = this.options.show_page || 1;
var template = this.templateLibraryList();
var libraries_to_render = null;
var models = null;
- if ( this.options.show_page === null || this.options.show_page < 1 ){
- this.options.show_page = 1;
- }
+ $( ".tooltip" ).hide();
if ( typeof options !== 'undefined' ){
models = typeof options.models !== 'undefined' ? options.models : null;
}
@@ -89,6 +79,10 @@
} else {
libraries_to_render = [];
}
+ // pagination
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
this.options.total_libraries_count = libraries_to_render.length
var page_start = ( Galaxy.libraries.preferences.get( 'library_page_size' ) * ( this.options.show_page - 1 ) );
this.options.page_count = Math.ceil( this.options.total_libraries_count / Galaxy.libraries.preferences.get( 'library_page_size' ) );
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b static/scripts/galaxy.library.js
--- a/static/scripts/galaxy.library.js
+++ b/static/scripts/galaxy.library.js
@@ -36,7 +36,7 @@
initialize: function() {
this.routesHit = 0;
//keep count of number of routes handled by the application
- Backbone.history.on('route', function() { this.routesHit++; }, this);
+ Backbone.history.on( 'route', function() { this.routesHit++; }, this );
},
routes: {
@@ -45,6 +45,7 @@
"library/:library_id/permissions" : "library_permissions",
"folders/:folder_id/permissions" : "folder_permissions",
"folders/:id" : "folder_content",
+ "folders/:id/page/:show_page" : "folder_page",
"folders/:folder_id/datasets/:dataset_id" : "dataset_detail",
"folders/:folder_id/datasets/:dataset_id/permissions" : "dataset_permissions",
"folders/:folder_id/datasets/:dataset_id/versions/:ldda_id" : "dataset_version",
@@ -53,13 +54,13 @@
},
back: function() {
- if(this.routesHit > 1) {
+ if( this.routesHit > 1 ) {
//more than one route hit -> user did not land to current page directly
window.history.back();
} else {
//otherwise go to the home page. Use replaceState if available so
//the navigation doesn't create an extra history entry
- this.navigate('#', {trigger:true, replace:true});
+ this.navigate( '#', { trigger:true, replace:true } );
}
}
});
@@ -71,7 +72,8 @@
with_deleted : false,
sort_order : 'asc',
sort_by : 'name',
- library_page_size : 20
+ library_page_size : 20,
+ folder_page_size : 15
}
});
@@ -94,10 +96,10 @@
this.library_router = new LibraryRouter();
- this.library_router.on('route:libraries', function() {
- Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
- Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
- });
+ this.library_router.on( 'route:libraries', function() {
+ Galaxy.libraries.libraryToolbarView = new mod_librarytoolbar_view.LibraryToolbarView();
+ Galaxy.libraries.libraryListView = new mod_librarylist_view.LibraryListView();
+ });
this.library_router.on('route:libraries_page', function( show_page ) {
if ( Galaxy.libraries.libraryToolbarView === null ){
@@ -108,66 +110,77 @@
}
});
- this.library_router.on('route:folder_content', function(id) {
+ this.library_router.on( 'route:folder_content', function( id ) {
if (Galaxy.libraries.folderToolbarView){
- Galaxy.libraries.folderToolbarView.$el.unbind('click');
- }
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: id});
- });
+ Galaxy.libraries.folderToolbarView.$el.unbind( 'click' );
+ }
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id } );
+ });
- this.library_router.on('route:download', function(folder_id, format) {
- if ($('#folder_list_body').find(':checked').length === 0) {
- mod_toastr.info( 'You must select at least one dataset to download' );
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: true, replace: true});
- } else {
- Galaxy.libraries.folderToolbarView.download(folder_id, format);
- Galaxy.libraries.library_router.navigate('folders/' + folder_id, {trigger: false, replace: true});
- }
- });
+ this.library_router.on( 'route:folder_page', function( id, show_page ) {
+ if ( Galaxy.libraries.folderToolbarView === null ){
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( {id: id} );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: id, show_page: show_page } );
+ } else {
+ Galaxy.libraries.folderListView.render( { id: id, show_page: parseInt( show_page ) } )
+ }
+ });
- this.library_router.on('route:dataset_detail', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
- });
- this.library_router.on('route:dataset_version', function(folder_id, dataset_id, ldda_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
- });
+ this.library_router.on( 'route:download', function( folder_id, format ) {
+ if ( $( '#folder_list_body' ).find( ':checked' ).length === 0 ) {
+ mod_toastr.info( 'You must select at least one dataset to download' );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: true, replace: true } );
+ } else {
+ Galaxy.libraries.folderToolbarView.download( folder_id, format );
+ Galaxy.libraries.library_router.navigate( 'folders/' + folder_id, { trigger: false, replace: true } );
+ }
+ });
- this.library_router.on('route:dataset_permissions', function(folder_id, dataset_id){
- if (Galaxy.libraries.datasetView){
- Galaxy.libraries.datasetView.$el.unbind('click');
- }
- Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_detail', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id});
+ });
- this.library_router.on('route:library_permissions', function(library_id){
- if (Galaxy.libraries.libraryView){
- Galaxy.libraries.libraryView.$el.unbind('click');
- }
- Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
- });
+ this.library_router.on( 'route:dataset_version', function(folder_id, dataset_id, ldda_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, ldda_id: ldda_id, show_version: true});
+ });
- this.library_router.on('route:folder_permissions', function(folder_id){
- if (Galaxy.libraries.folderView){
- Galaxy.libraries.folderView.$el.unbind('click');
- }
- Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
- });
- this.library_router.on('route:import_datasets', function(folder_id, source){
- if (Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView){
- Galaxy.libraries.folderToolbarView.showImportModal({source:source});
- } else {
- Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView({id: folder_id});
- Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView({id: folder_id});
- Galaxy.libraries.folderToolbarView.showImportModal({source: source});
- }
- });
+ this.library_router.on( 'route:dataset_permissions', function(folder_id, dataset_id){
+ if (Galaxy.libraries.datasetView){
+ Galaxy.libraries.datasetView.$el.unbind('click');
+ }
+ Galaxy.libraries.datasetView = new mod_library_dataset_view.LibraryDatasetView({id: dataset_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:library_permissions', function(library_id){
+ if (Galaxy.libraries.libraryView){
+ Galaxy.libraries.libraryView.$el.unbind('click');
+ }
+ Galaxy.libraries.libraryView = new mod_library_library_view.LibraryView({id: library_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:folder_permissions', function(folder_id){
+ if (Galaxy.libraries.folderView){
+ Galaxy.libraries.folderView.$el.unbind('click');
+ }
+ Galaxy.libraries.folderView = new mod_library_folder_view.FolderView({id: folder_id, show_permissions: true});
+ });
+
+ this.library_router.on( 'route:import_datasets', function( folder_id, source ){
+ if ( Galaxy.libraries.folderToolbarView && Galaxy.libraries.folderListView ){
+ Galaxy.libraries.folderToolbarView.showImportModal( { source:source } );
+ } else {
+ Galaxy.libraries.folderToolbarView = new mod_foldertoolbar_view.FolderToolbarView( { id: folder_id } );
+ Galaxy.libraries.folderListView = new mod_folderlist_view.FolderListView( { id: folder_id } );
+ Galaxy.libraries.folderToolbarView.showImportModal( { source: source } );
+ }
+ });
Backbone.history.start({pushState: false});
}
diff -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 -r 20942ced453dc9f31b2d238855d1b8f5da3f078b static/scripts/mvc/library/library-folderlist-view.js
--- a/static/scripts/mvc/library/library-folderlist-view.js
+++ b/static/scripts/mvc/library/library-folderlist-view.js
@@ -15,322 +15,359 @@
) {
var FolderListView = Backbone.View.extend({
- el : '#folder_items_element',
- defaults: {
- 'include_deleted' : false
- },
- // progress percentage
- progress: 0,
- // progress rate per one item
- progressStep: 1,
- // self modal
- modal : null,
+ el : '#folder_items_element',
+ // progress percentage
+ progress: 0,
+ // progress rate per one item
+ progressStep: 1,
- folderContainer: null,
+ folderContainer: null,
- sort: 'asc',
+ sort: 'asc',
- events: {
- 'click #select-all-checkboxes' : 'selectAll',
- 'click .dataset_row' : 'selectClickedRow',
- 'click .sort-folder-link' : 'sortColumnClicked'
- },
+ events: {
+ 'click #select-all-checkboxes' : 'selectAll',
+ 'click .dataset_row' : 'selectClickedRow',
+ 'click .sort-folder-link' : 'sortColumnClicked'
+ },
- // cache of rendered views
- rowViews: {},
-
- initialize : function(options){
- this.options = _.defaults(this.options || {}, options);
- this.fetchFolder();
- },
+ collection: null,
- fetchFolder: function(options){
- var options = options || {};
- this.options.include_deleted = options.include_deleted;
- var that = this;
+ defaults: {
+ include_deleted: false,
+ page_count: null,
+ show_page: null
+ },
- this.collection = new mod_library_model.Folder();
+ /**
+ * Initialize and fetch the folder from the server.
+ * @param {object} options an object with options
+ */
+ initialize : function( options ){
+ this.options = _.defaults( this.options || {}, this.defaults, options );
+ this.modal = null;
+ // map of folder item ids to item views = cache
+ this.rowViews = {};
- // start to listen if someone modifies collection
- this.listenTo(this.collection, 'add', this.renderOne);
- this.listenTo(this.collection, 'remove', this.removeOne);
+ // create a collection of folder items for this view
+ this.collection = new mod_library_model.Folder();
- this.folderContainer = new mod_library_model.FolderContainer({id: this.options.id});
- this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
- if (this.options.include_deleted){
- this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
- }
- this.folderContainer.fetch({
- success: function(folder_container) {
- that.folder_container = folder_container;
- that.render();
- that.addAll(folder_container.get('folder').models);
- if (that.options.dataset_id){
- row = _.findWhere(that.rowViews, {id: that.options.dataset_id});
- if (row) {
+ // start to listen if someone modifies the collection
+ this.listenTo( this.collection, 'add', this.renderOne );
+ this.listenTo( this.collection, 'remove', this.removeOne );
+
+ this.fetchFolder();
+ },
+
+ fetchFolder: function( options ){
+ var options = options || {};
+ this.options.include_deleted = options.include_deleted;
+ var that = this;
+
+ this.folderContainer = new mod_library_model.FolderContainer( { id: this.options.id } );
+ this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
+
+ if ( this.options.include_deleted ){
+ this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
+ }
+ this.folderContainer.fetch({
+ success: function( folder_container ) {
+ that.folder_container = folder_container;
+ that.render();
+ },
+ error: function( model, response ){
+ if ( typeof response.responseJSON !== "undefined" ){
+ mod_toastr.error( response.responseJSON.err_msg + ' Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ } else {
+ mod_toastr.error( 'An error ocurred. Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
+ }
+ }
+ });
+ },
+
+ render: function ( options ){
+ this.options = _.extend( this.options, options );
+ var template = this.templateFolder();
+ $(".tooltip").hide();
+
+ // find the upper id in the full path
+ var path = this.folderContainer.attributes.metadata.full_path;
+ var upper_folder_id;
+ if ( path.length === 1 ){ // the library is above us
+ upper_folder_id = 0;
+ } else {
+ upper_folder_id = path[ path.length-2 ][ 0 ];
+ }
+
+ this.$el.html( template( {
+ path: this.folderContainer.attributes.metadata.full_path,
+ parent_library_id: this.folderContainer.attributes.metadata.parent_library_id,
+ id: this.options.id,
+ upper_folder_id: upper_folder_id,
+ order: this.sort
+ } ) );
+
+ // when dataset_id is present render its details too
+ if ( this.options.dataset_id ){
+ row = _.findWhere( that.rowViews, { id: this.options.dataset_id } );
+ if ( row ) {
row.showDatasetDetails();
} else {
- mod_toastr.error('Dataset not found. Showing folder instead.');
+ mod_toastr.error( 'Requested dataset not found. Showing folder instead.' );
}
+ } else {
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.paginate();
+ }
+ $("#center [data-toggle]").tooltip();
+ $("#center").css('overflow','auto');
+ },
+
+ paginate: function( options ){
+ this.options = _.extend( this.options, options );
+
+ if ( this.options.show_page === null || this.options.show_page < 1 ){
+ this.options.show_page = 1;
+ }
+ this.options.total_items_count = this.folder_container.get( 'folder' ).models.length;
+ this.options.page_count = Math.ceil( this.options.total_items_count / Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ var page_start = ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * ( this.options.show_page - 1 ) );
+ var items_to_render = null;
+ items_to_render = this.folder_container.get( 'folder' ).models.slice( page_start, page_start + Galaxy.libraries.preferences.get( 'folder_page_size' ) );
+ this.options.items_shown = items_to_render.length;
+ // User requests page with no items
+ if ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * this.options.show_page > ( this.options.total_items_count + Galaxy.libraries.preferences.get( 'folder_page_size' ) ) ){
+ items_to_render = [];
+ }
+ Galaxy.libraries.folderToolbarView.renderPaginator( this.options );
+ this.collection.reset();
+ this.addAll( items_to_render )
+ },
+
+ /**
+ * Adds all given models to the collection.
+ * @param {array of Item or FolderAsModel} array of models that should
+ * be added to the view's collection.
+ */
+ addAll: function( models ){
+ _.each(models, function( model ) {
+ Galaxy.libraries.folderListView.collection.add( model );
+ });
+ $( "#center [data-toggle]" ).tooltip();
+ this.checkEmptiness();
+ this.postRender();
+ },
+
+ /**
+ * Call this after all models are added to the collection
+ * to ensure that the folder toolbar will show proper options
+ * and that event will be bound on all subviews.
+ */
+ postRender: function(){
+ var fetched_metadata = this.folderContainer.attributes.metadata;
+ fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
+ Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * Iterates this view's collection and calls the render
+ * function for each. Also binds the hover behavior.
+ */
+ renderAll: function(){
+ var that = this;
+ _.each( this.collection.models.reverse(), function( model ) {
+ that.renderOne( model );
+ });
+ this.postRender();
+ },
+
+ /**
+ * Creates a view for the given model and adds it to the folder view.
+ * @param {Item or FolderAsModel} model of the view that will be rendered
+ */
+ renderOne: function(model){
+ if (model.get('type') !== 'folder'){
+ this.options.contains_file = true;
+ // model.set('readable_size', this.size_to_string(model.get('file_size')));
}
- },
- error: function(model, response){
- if (typeof response.responseJSON !== "undefined"){
- mod_toastr.error(response.responseJSON.err_msg + ' Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- } else {
- mod_toastr.error('An error ocurred. Click this to go back.', '', {onclick: function() {Galaxy.libraries.library_router.back();}});
- }
+ model.set('folder_id', this.id);
+ var rowView = new mod_library_folderrow_view.FolderRowView(model);
+
+ // save new rowView to cache
+ this.rowViews[model.get('id')] = rowView;
+
+ this.$el.find('#first_folder_item').after(rowView.el);
+
+ $('.library-row').hover(function() {
+ $(this).find('.show_on_hover').show();
+ }, function () {
+ $(this).find('.show_on_hover').hide();
+ });
+ },
+
+ /**
+ * removes the view of the given model from the DOM
+ * @param {Item or FolderAsModel} model of the view that will be removed
+ */
+ removeOne: function( model ){
+ this.$el.find( '#' + model.id ).remove();
+ },
+
+ /** Checks whether the list is empty and adds/removes the message */
+ checkEmptiness : function(){
+ if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
+ this.$el.find('.empty-folder-message').show();
+ } else {
+ this.$el.find('.empty-folder-message').hide();
}
- });
- },
+ },
- render: function (options) {
- this.options = _.defaults(this.options, options);
- var template = this.templateFolder();
- $(".tooltip").hide();
+ /** User clicked the table heading = he wants to sort stuff */
+ sortColumnClicked : function(event){
+ event.preventDefault();
+ if (this.sort === 'asc'){
+ this.sortFolder('name','desc');
+ this.sort = 'desc';
+ } else {
+ this.sortFolder('name','asc');
+ this.sort = 'asc';
+ }
+ this.render();
+ this.renderAll();
+ this.checkEmptiness();
+ },
- // TODO move to server
- // find the upper id in the full path
- var path = this.folderContainer.attributes.metadata.full_path;
- var upper_folder_id;
- if (path.length === 1){ // the library is above us
- upper_folder_id = 0;
- } else {
- upper_folder_id = path[path.length-2][0];
+ /**
+ * Sorts the underlying collection according to the parameters received.
+ * Currently supports only sorting by name.
+ */
+ sortFolder: function(sort_by, order){
+ if (sort_by === 'name'){
+ if (order === 'asc'){
+ return this.collection.sortByNameAsc();
+ } else if (order === 'desc'){
+ return this.collection.sortByNameDesc();
+ }
+ }
+ },
+
+ /**
+ * User clicked the checkbox in the table heading
+ * @param {context} event
+ */
+ selectAll : function (event) {
+ var selected = event.target.checked;
+ that = this;
+ // Iterate each checkbox
+ $(':checkbox', '#folder_list_body').each(function() {
+ this.checked = selected;
+ $row = $(this.parentElement.parentElement);
+ // Change color of selected/unselected
+ if (selected) {
+ that.makeDarkRow($row);
+ } else {
+ that.makeWhiteRow($row);
+ }
+ });
+ },
+
+ /**
+ * Check checkbox if user clicks on the whole row or
+ * on the checkbox itself
+ */
+ selectClickedRow : function (event) {
+ var checkbox = '';
+ var $row;
+ var source;
+ if (event.target.localName === 'input'){
+ checkbox = event.target;
+ $row = $(event.target.parentElement.parentElement);
+ source = 'input';
+ } else if (event.target.localName === 'td') {
+ checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
+ $row = $(event.target.parentElement);
+ source = 'td';
+ }
+ if (checkbox.checked){
+ if (source==='td'){
+ checkbox.checked = '';
+ this.makeWhiteRow($row);
+ } else if (source==='input') {
+ this.makeDarkRow($row);
+ }
+ } else {
+ if (source==='td'){
+ checkbox.checked = 'selected';
+ this.makeDarkRow($row);
+ } else if (source==='input') {
+ this.makeWhiteRow($row);
+ }
+ }
+ },
+
+ makeDarkRow: function($row){
+ $row.removeClass('light').addClass('dark');
+ $row.find('a').removeClass('light').addClass('dark');
+ $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
+ },
+
+ makeWhiteRow: function($row){
+ $row.removeClass('dark').addClass('light');
+ $row.find('a').removeClass('dark').addClass('light');
+ $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
+ },
+
+ templateFolder : function (){
+ var tmpl_array = [];
+
+ // BREADCRUMBS
+ tmpl_array.push('<ol class="breadcrumb">');
+ tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
+ tmpl_array.push(' <% _.each(path, function(path_item) { %>');
+ tmpl_array.push(' <% if (path_item[0] != id) { %>');
+ tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
+ tmpl_array.push( '<% } else { %>');
+ tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
+ tmpl_array.push(' <% } %>');
+ tmpl_array.push(' <% }); %>');
+ tmpl_array.push('</ol>');
+
+ // FOLDER CONTENT
+ tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
+ tmpl_array.push(' <thead>');
+ tmpl_array.push(' <th class="button_heading"></th>');
+ tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
+ tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
+ tmpl_array.push(' <th style="width:5%;">data type</th>');
+ tmpl_array.push(' <th style="width:10%;">size</th>');
+ tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
+ tmpl_array.push(' <th style="width:10%;"></th> ');
+ tmpl_array.push(' </thead>');
+ tmpl_array.push(' <tbody id="folder_list_body">');
+ tmpl_array.push(' <tr id="first_folder_item">');
+ tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' <td></td>');
+ tmpl_array.push(' </tr>');
+
+ tmpl_array.push(' </tbody>');
+ tmpl_array.push('</table>');
+ tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
+
+ return _.template(tmpl_array.join(''));
}
-
- this.$el.html(template({ path: this.folderContainer.attributes.metadata.full_path, parent_library_id: this.folderContainer.attributes.metadata.parent_library_id, id: this.options.id, upper_folder_id: upper_folder_id, order: this.sort}));
-
- // initialize the library tooltips
- $("#center [data-toggle]").tooltip();
- //hack to show scrollbars
- $("#center").css('overflow','auto');
- },
-
- /**
- * Call this after all models are added to the collection
- * to ensure that the folder toolbar will show proper options
- * and that event will be bound on all subviews.
- */
- postRender: function(){
- var fetched_metadata = this.folderContainer.attributes.metadata;
- fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
- Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * Adds all given models to the collection.
- * @param {array of Item or FolderAsModel} array of models that should
- * be added to the view's collection.
- */
- addAll: function(models){
- _.each(models.reverse(), function(model) {
- Galaxy.libraries.folderListView.collection.add(model);
- });
-
- $("#center [data-toggle]").tooltip();
- this.checkEmptiness();
-
- this.postRender();
- },
-
- /**
- * Iterates this view's collection and calls the render
- * function for each. Also binds the hover behavior.
- */
- renderAll: function(){
- var that = this;
- _.each(this.collection.models.reverse(), function(model) {
- that.renderOne(model);
- });
- this.postRender();
- },
-
- /**
- * Creates a view for the given model and adds it to the folder view.
- * @param {Item or FolderAsModel} model of the view that will be rendered
- */
- renderOne: function(model){
- if (model.get('type') !== 'folder'){
- this.options.contains_file = true;
- // model.set('readable_size', this.size_to_string(model.get('file_size')));
- }
- model.set('folder_id', this.id);
- var rowView = new mod_library_folderrow_view.FolderRowView(model);
-
- // save new rowView to cache
- this.rowViews[model.get('id')] = rowView;
-
- this.$el.find('#first_folder_item').after(rowView.el);
-
- $('.library-row').hover(function() {
- $(this).find('.show_on_hover').show();
- }, function () {
- $(this).find('.show_on_hover').hide();
- });
- },
-
- /**
- * removes the view of the given model from the DOM
- * @param {Item or FolderAsModel} model of the view that will be removed
- */
- removeOne: function(model){
- this.$el.find('#' + model.id).remove();
- },
-
- /** Checks whether the list is empty and adds/removes the message */
- checkEmptiness : function(){
- if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
- this.$el.find('.empty-folder-message').show();
- } else {
- this.$el.find('.empty-folder-message').hide();
- }
- },
-
- /** User clicked the table heading = he wants to sort stuff */
- sortColumnClicked : function(event){
- event.preventDefault();
- if (this.sort === 'asc'){
- this.sortFolder('name','desc');
- this.sort = 'desc';
- } else {
- this.sortFolder('name','asc');
- this.sort = 'asc';
- }
- this.render();
- this.renderAll();
- this.checkEmptiness();
- },
-
- /**
- * Sorts the underlying collection according to the parameters received.
- * Currently supports only sorting by name.
- */
- sortFolder: function(sort_by, order){
- if (sort_by === 'name'){
- if (order === 'asc'){
- return this.collection.sortByNameAsc();
- } else if (order === 'desc'){
- return this.collection.sortByNameDesc();
- }
- }
- },
-
- /**
- * User clicked the checkbox in the table heading
- * @param {context} event
- */
- selectAll : function (event) {
- var selected = event.target.checked;
- that = this;
- // Iterate each checkbox
- $(':checkbox', '#folder_list_body').each(function() {
- this.checked = selected;
- $row = $(this.parentElement.parentElement);
- // Change color of selected/unselected
- if (selected) {
- that.makeDarkRow($row);
- } else {
- that.makeWhiteRow($row);
- }
- });
- },
-
- /**
- * Check checkbox if user clicks on the whole row or
- * on the checkbox itself
- */
- selectClickedRow : function (event) {
- var checkbox = '';
- var $row;
- var source;
- if (event.target.localName === 'input'){
- checkbox = event.target;
- $row = $(event.target.parentElement.parentElement);
- source = 'input';
- } else if (event.target.localName === 'td') {
- checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
- $row = $(event.target.parentElement);
- source = 'td';
- }
- if (checkbox.checked){
- if (source==='td'){
- checkbox.checked = '';
- this.makeWhiteRow($row);
- } else if (source==='input') {
- this.makeDarkRow($row);
- }
- } else {
- if (source==='td'){
- checkbox.checked = 'selected';
- this.makeDarkRow($row);
- } else if (source==='input') {
- this.makeWhiteRow($row);
- }
- }
- },
-
- makeDarkRow: function($row){
- $row.removeClass('light').addClass('dark');
- $row.find('a').removeClass('light').addClass('dark');
- $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
- },
-
- makeWhiteRow: function($row){
- $row.removeClass('dark').addClass('light');
- $row.find('a').removeClass('dark').addClass('light');
- $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
- },
-
- templateFolder : function (){
- var tmpl_array = [];
-
- // BREADCRUMBS
- tmpl_array.push('<ol class="breadcrumb">');
- tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
- tmpl_array.push(' <% _.each(path, function(path_item) { %>');
- tmpl_array.push(' <% if (path_item[0] != id) { %>');
- tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a></li> ');
- tmpl_array.push( '<% } else { %>');
- tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
- tmpl_array.push(' <% } %>');
- tmpl_array.push(' <% }); %>');
- tmpl_array.push('</ol>');
-
- // FOLDER CONTENT
- tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
- tmpl_array.push(' <thead>');
- tmpl_array.push(' <th class="button_heading"></th>');
- tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
- tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a><span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
- tmpl_array.push(' <th style="width:5%;">data type</th>');
- tmpl_array.push(' <th style="width:10%;">size</th>');
- tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
- tmpl_array.push(' <th style="width:10%;"></th> ');
- tmpl_array.push(' </thead>');
- tmpl_array.push(' <tbody id="folder_list_body">');
- tmpl_array.push(' <tr id="first_folder_item">');
- tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' <td></td>');
- tmpl_array.push(' </tr>');
-
- tmpl_array.push(' </tbody>');
- tmpl_array.push('</table>');
- tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
-
- return _.template(tmpl_array.join(''));
- }
-
+
});
return {
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/77f9f54744d4/
Changeset: 77f9f54744d4
Branch: next-stable
User: guerler
Date: 2014-12-03 22:29:34+00:00
Summary: ToolForm: Add data collection parameter
Affected #: 7 files
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -307,6 +307,11 @@
field = this._fieldData(input_def);
break;
+ // collection selector
+ //case 'data_collection':
+ // field = this._fieldData(input_def);
+ // break;
+
// data column
case 'data_column':
field = this._fieldSelect(input_def);
@@ -383,6 +388,7 @@
id : 'field-' + input_def.id,
extensions : input_def.extensions,
multiple : input_def.multiple,
+ type : input_def.type,
data : input_def.options,
onchange : function() {
self.app.refresh();
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb client/galaxy/scripts/mvc/tools/tools-select-content.js
--- a/client/galaxy/scripts/mvc/tools/tools-select-content.js
+++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js
@@ -20,15 +20,23 @@
// radio button options
var radio_buttons = [];
+ // identify selector type
+ if (options.type == 'data_collection') {
+ this.mode = 'collection';
+ } else {
+ if (options.multiple) {
+ this.mode = 'multiple';
+ } else {
+ this.mode = 'single';
+ }
+ }
+
// set initial state
- if (!options.multiple) {
- this.current = 'single';
- } else {
- this.current = 'multiple';
- }
-
+ this.current = this.mode;
+ this.list = {};
+
// add single dataset selector
- if (!options.multiple) {
+ if (this.mode == 'single') {
radio_buttons.push({icon: 'fa-file-o', label : 'Single dataset', value : 'single'});
this.select_single = new Ui.Select.View({
onchange : function() {
@@ -42,29 +50,33 @@
}
// add multiple dataset selector
- radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
- this.select_multiple = new Ui.Select.View({
- multiple : true,
- onchange : function() {
- self.trigger('change');
- }
- });
- this.list['multiple'] = {
- field: this.select_multiple,
- type : 'hda'
- };
+ if (this.mode == 'single' || this.mode == 'multiple') {
+ radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
+ this.select_multiple = new Ui.Select.View({
+ multiple : true,
+ onchange : function() {
+ self.trigger('change');
+ }
+ });
+ this.list['multiple'] = {
+ field: this.select_multiple,
+ type : 'hda'
+ };
+ }
// add collection selector
- radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
- this.select_collection = new Ui.Select.View({
- onchange : function() {
- self.trigger('change');
- }
- });
- this.list['collection'] = {
- field: this.select_collection,
- type : 'hdca'
- };
+ if (this.mode == 'single' || this.mode == 'collection') {
+ radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
+ this.select_collection = new Ui.Select.View({
+ onchange : function() {
+ self.trigger('change');
+ }
+ });
+ this.list['collection'] = {
+ field: this.select_collection,
+ type : 'hdca'
+ };
+ }
// create button
this.button_type = new Ui.RadioButton.View({
@@ -81,7 +93,9 @@
this.$batch = $(ToolTemplate.batchMode());
// add elements to dom
- this.$el.append(Utils.wrap(this.button_type.$el));
+ if (_.size(this.list) > 1) {
+ this.$el.append(Utils.wrap(this.button_type.$el));
+ }
for (var i in this.list) {
this.$el.append(this.list[i].field.$el);
}
@@ -144,8 +158,8 @@
// update selection fields
this.select_single && this.select_single.update(dataset_options);
- this.select_multiple.update(dataset_options);
- this.select_collection.update(collection_options);
+ this.select_multiple && this.select_multiple.update(dataset_options);
+ this.select_collection && this.select_collection.update(collection_options);
// add to content list
this.app.content.add(options);
@@ -167,7 +181,7 @@
this.current = 'collection';
this.select_collection.value(list[0]);
} else {
- if (list.length > 1 || this.options.multiple) {
+ if (this.mode == 'multiple') {
this.current = 'multiple';
this.select_multiple.value(list);
} else {
@@ -195,7 +209,7 @@
// prepare result dict
var result = {
- batch : !this.options.multiple && this.current != 'single',
+ batch : this.mode == 'single' && this.current != 'single',
values : []
}
@@ -227,7 +241,7 @@
$el.hide();
}
}
- if (this.current != 'single' && !this.options.multiple) {
+ if (this.mode == 'single' && this.current != 'single') {
this.$batch.show();
} else {
this.$batch.hide();
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -2310,6 +2310,47 @@
return d
+ def to_dict( self, trans, view='collection', value_mapper=None, other_values=None ):
+ # create dictionary and fill default parameters
+ d = super( DataCollectionToolParameter, self ).to_dict( trans )
+ d['multiple'] = self.multiple
+ d['is_dynamic'] = False
+ d['options'] = {'hda': [], 'hdca': []}
+
+ # return default content if context is not available
+ if other_values is None:
+ return d
+
+ # prepare dataset/collection matching
+ dataset_matcher = DatasetMatcher( trans, self, None, other_values )
+ history = trans.history
+
+ # append directly matched collections
+ for hdca in self.match_collections( trans, history, dataset_matcher ):
+ d['options']['hdca'].append({
+ 'id' : trans.security.encode_id( hdca.id ),
+ 'id_uncoded' : hdca.id,
+ 'hid' : hdca.hid,
+ 'name' : hdca.name,
+ 'src' : 'hdca'
+ })
+
+ # append matching subcollections
+ for hdca in self.match_multirun_collections( trans, history, dataset_matcher ):
+ subcollection_type = self._history_query( trans ).collection_type_description.collection_type
+ d['options']['hdca'].append({
+ 'id' : trans.security.encode_id( hdca.id ),
+ 'id_uncoded' : hdca.id,
+ 'hid' : hdca.hid,
+ 'name' : hdca.name,
+ 'src' : 'hdca'
+ })
+
+ # sort both lists
+ d['options']['hdca'] = sorted(d['options']['hdca'], key=lambda k: k['hid'], reverse=True)
+
+ # return final dictionary
+ return d
class HiddenDataToolParameter( HiddenToolParameter, DataToolParameter ):
"""
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -307,6 +307,11 @@
field = this._fieldData(input_def);
break;
+ // collection selector
+ //case 'data_collection':
+ // field = this._fieldData(input_def);
+ // break;
+
// data column
case 'data_column':
field = this._fieldSelect(input_def);
@@ -383,6 +388,7 @@
id : 'field-' + input_def.id,
extensions : input_def.extensions,
multiple : input_def.multiple,
+ type : input_def.type,
data : input_def.options,
onchange : function() {
self.app.refresh();
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb static/scripts/mvc/tools/tools-select-content.js
--- a/static/scripts/mvc/tools/tools-select-content.js
+++ b/static/scripts/mvc/tools/tools-select-content.js
@@ -20,15 +20,23 @@
// radio button options
var radio_buttons = [];
+ // identify selector type
+ if (options.type == 'data_collection') {
+ this.mode = 'collection';
+ } else {
+ if (options.multiple) {
+ this.mode = 'multiple';
+ } else {
+ this.mode = 'single';
+ }
+ }
+
// set initial state
- if (!options.multiple) {
- this.current = 'single';
- } else {
- this.current = 'multiple';
- }
-
+ this.current = this.mode;
+ this.list = {};
+
// add single dataset selector
- if (!options.multiple) {
+ if (this.mode == 'single') {
radio_buttons.push({icon: 'fa-file-o', label : 'Single dataset', value : 'single'});
this.select_single = new Ui.Select.View({
onchange : function() {
@@ -42,29 +50,33 @@
}
// add multiple dataset selector
- radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
- this.select_multiple = new Ui.Select.View({
- multiple : true,
- onchange : function() {
- self.trigger('change');
- }
- });
- this.list['multiple'] = {
- field: this.select_multiple,
- type : 'hda'
- };
+ if (this.mode == 'single' || this.mode == 'multiple') {
+ radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
+ this.select_multiple = new Ui.Select.View({
+ multiple : true,
+ onchange : function() {
+ self.trigger('change');
+ }
+ });
+ this.list['multiple'] = {
+ field: this.select_multiple,
+ type : 'hda'
+ };
+ }
// add collection selector
- radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
- this.select_collection = new Ui.Select.View({
- onchange : function() {
- self.trigger('change');
- }
- });
- this.list['collection'] = {
- field: this.select_collection,
- type : 'hdca'
- };
+ if (this.mode == 'single' || this.mode == 'collection') {
+ radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
+ this.select_collection = new Ui.Select.View({
+ onchange : function() {
+ self.trigger('change');
+ }
+ });
+ this.list['collection'] = {
+ field: this.select_collection,
+ type : 'hdca'
+ };
+ }
// create button
this.button_type = new Ui.RadioButton.View({
@@ -81,7 +93,9 @@
this.$batch = $(ToolTemplate.batchMode());
// add elements to dom
- this.$el.append(Utils.wrap(this.button_type.$el));
+ if (_.size(this.list) > 1) {
+ this.$el.append(Utils.wrap(this.button_type.$el));
+ }
for (var i in this.list) {
this.$el.append(this.list[i].field.$el);
}
@@ -144,8 +158,8 @@
// update selection fields
this.select_single && this.select_single.update(dataset_options);
- this.select_multiple.update(dataset_options);
- this.select_collection.update(collection_options);
+ this.select_multiple && this.select_multiple.update(dataset_options);
+ this.select_collection && this.select_collection.update(collection_options);
// add to content list
this.app.content.add(options);
@@ -167,7 +181,7 @@
this.current = 'collection';
this.select_collection.value(list[0]);
} else {
- if (list.length > 1 || this.options.multiple) {
+ if (this.mode == 'multiple') {
this.current = 'multiple';
this.select_multiple.value(list);
} else {
@@ -195,7 +209,7 @@
// prepare result dict
var result = {
- batch : !this.options.multiple && this.current != 'single',
+ batch : this.mode == 'single' && this.current != 'single',
values : []
}
@@ -227,7 +241,7 @@
$el.hide();
}
}
- if (this.current != 'single' && !this.options.multiple) {
+ if (this.mode == 'single' && this.current != 'single') {
this.$batch.show();
} else {
this.$batch.hide();
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
diff -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 -r 77f9f54744d480948aec2f0662657139f35f87fb static/scripts/packed/mvc/tools/tools-select-content.js
--- a/static/scripts/packed/mvc/tools/tools-select-content.js
+++ b/static/scripts/packed/mvc/tools/tools-select-content.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(k,g){this.app=k;this.options=g;var f=this;this.setElement("<div/>");this.list={};var j=[];if(!g.multiple){this.current="single"}else{this.current="multiple"}if(!g.multiple){j.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}j.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,onchange:function(){f.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"};j.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"};this.button_type=new e.RadioButton.View({value:this.current,data:j,onchange:function(i){f.current=i;f.refresh();f.trigger("change")}});this.$batch=$(a.batchMode());this.$el.append(c.wrap(this.button_type.$el));for(var h in this.list){this.$el.append(this.list[h].field.$el)}this.$el.append(this.$batch);this.update(g.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(g.onchange){g.onchange(f.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple.update(l);this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(l.length>1||this.options.multiple){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:!this.options.multiple&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.current!="single"&&!this.options.multiple){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(k,g){this.app=k;this.options=g;var f=this;this.setElement("<div/>");this.list={};var j=[];if(g.type=="data_collection"){this.mode="collection"}else{if(g.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};if(this.mode=="single"){j.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){j.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,onchange:function(){f.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){j.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:j,onchange:function(i){f.current=i;f.refresh();f.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var h in this.list){this.$el.append(this.list[h].field.$el)}this.$el.append(this.$batch);this.update(g.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(g.onchange){g.onchange(f.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/97f0146a1ff0/
Changeset: 97f0146a1ff0
Branch: next-stable
User: guerler
Date: 2014-12-04 16:45:18+00:00
Summary: ToolForm: Add dataset types to error message
Affected #: 15 files
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c client/galaxy/scripts/mvc/tools/tools-form.js
--- a/client/galaxy/scripts/mvc/tools/tools-form.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form.js
@@ -340,7 +340,7 @@
buttons: {
execute : new Ui.Button({
icon : 'fa-check',
- tooltip : 'Execute the tool',
+ tooltip : 'Execute: ' + self.model.name,
title : 'Execute',
cls : 'btn btn-primary',
floating : 'clear',
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -314,6 +314,7 @@
// data column
case 'data_column':
+ input_def.error_text = 'Referenced dataset contains no suitable columns';
field = this._fieldSelect(input_def);
break;
@@ -425,6 +426,7 @@
return new SelectClass.View({
id : 'field-' + input_def.id,
data : options,
+ error_text : input_def.error_text || 'No options available',
multiple : input_def.multiple,
searchable : input_def.searchable,
onchange : function() {
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c client/galaxy/scripts/mvc/tools/tools-select-content.js
--- a/client/galaxy/scripts/mvc/tools/tools-select-content.js
+++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js
@@ -35,10 +35,29 @@
this.current = this.mode;
this.list = {};
+ // error messages
+ var extensions = options.extensions.toString();
+ if (extensions) {
+ extensions = extensions.replace(',', ', ');
+ var pos = extensions.lastIndexOf(', ');
+ if (pos != -1) {
+ extensions = extensions.substr(0, pos) + " or " + extensions.substr(pos+1);
+ }
+ }
+ var hda_error = 'No dataset available';
+ if (extensions) {
+ hda_error = 'No dataset of type ' + extensions + ' available.';
+ }
+ var hdca_error = 'No dataset list available';
+ if (extensions) {
+ hdca_error = 'No dataset list of type ' + extensions + ' available.';
+ }
+
// add single dataset selector
if (this.mode == 'single') {
radio_buttons.push({icon: 'fa-file-o', label : 'Single dataset', value : 'single'});
this.select_single = new Ui.Select.View({
+ error_text : hda_error,
onchange : function() {
self.trigger('change');
}
@@ -54,6 +73,7 @@
radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
this.select_multiple = new Ui.Select.View({
multiple : true,
+ error_text : hda_error,
onchange : function() {
self.trigger('change');
}
@@ -68,6 +88,7 @@
if (this.mode == 'single' || this.mode == 'collection') {
radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
this.select_collection = new Ui.Select.View({
+ error_text : hdca_error,
onchange : function() {
self.trigger('change');
}
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c client/galaxy/scripts/mvc/ui/ui-options.js
--- a/client/galaxy/scripts/mvc/ui/ui-options.js
+++ b/client/galaxy/scripts/mvc/ui/ui-options.js
@@ -10,8 +10,8 @@
visible : true,
data : [],
id : Utils.uuid(),
- errorText : 'No data available.',
- waitText : 'Please wait...'
+ error_text : 'No data available.',
+ wait_text : 'Please wait...'
};
// configure options
@@ -153,7 +153,7 @@
*/
wait: function() {
if (this._size() == 0) {
- this._messageShow(this.options.waitText, 'info');
+ this._messageShow(this.options.wait_text, 'info');
this.$options.hide();
}
},
@@ -177,7 +177,7 @@
*/
_refresh: function() {
if (this._size() == 0) {
- this._messageShow(this.options.errorText, 'danger');
+ this._messageShow(this.options.error_text, 'danger');
this.$options.hide();
} else {
this._messageHide();
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c client/galaxy/scripts/mvc/ui/ui-select-default.js
--- a/client/galaxy/scripts/mvc/ui/ui-select-default.js
+++ b/client/galaxy/scripts/mvc/ui/ui-select-default.js
@@ -9,7 +9,7 @@
optionsDefault : {
id : '',
cls : '',
- empty : 'No data available',
+ error_text : 'No data available',
visible : true,
wait : false,
multiple : false,
@@ -247,7 +247,7 @@
this.disable();
// append placeholder
- this.$select.append(this._templateOption({value : 'null', label : this.options.empty}));
+ this.$select.append(this._templateOption({value : 'null', label : this.options.error_text}));
} else {
// enable select field
this.enable();
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -340,7 +340,7 @@
buttons: {
execute : new Ui.Button({
icon : 'fa-check',
- tooltip : 'Execute the tool',
+ tooltip : 'Execute: ' + self.model.name,
title : 'Execute',
cls : 'btn btn-primary',
floating : 'clear',
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -314,6 +314,7 @@
// data column
case 'data_column':
+ input_def.error_text = 'Referenced dataset contains no suitable columns';
field = this._fieldSelect(input_def);
break;
@@ -425,6 +426,7 @@
return new SelectClass.View({
id : 'field-' + input_def.id,
data : options,
+ error_text : input_def.error_text || 'No options available',
multiple : input_def.multiple,
searchable : input_def.searchable,
onchange : function() {
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/mvc/tools/tools-select-content.js
--- a/static/scripts/mvc/tools/tools-select-content.js
+++ b/static/scripts/mvc/tools/tools-select-content.js
@@ -35,10 +35,29 @@
this.current = this.mode;
this.list = {};
+ // error messages
+ var extensions = options.extensions.toString();
+ if (extensions) {
+ extensions = extensions.replace(',', ', ');
+ var pos = extensions.lastIndexOf(', ');
+ if (pos != -1) {
+ extensions = extensions.substr(0, pos) + " or " + extensions.substr(pos+1);
+ }
+ }
+ var hda_error = 'No dataset available';
+ if (extensions) {
+ hda_error = 'No dataset of type ' + extensions + ' available.';
+ }
+ var hdca_error = 'No dataset list available';
+ if (extensions) {
+ hdca_error = 'No dataset list of type ' + extensions + ' available.';
+ }
+
// add single dataset selector
if (this.mode == 'single') {
radio_buttons.push({icon: 'fa-file-o', label : 'Single dataset', value : 'single'});
this.select_single = new Ui.Select.View({
+ error_text : hda_error,
onchange : function() {
self.trigger('change');
}
@@ -54,6 +73,7 @@
radio_buttons.push({icon: 'fa-files-o', label : 'Multiple datasets', value : 'multiple' });
this.select_multiple = new Ui.Select.View({
multiple : true,
+ error_text : hda_error,
onchange : function() {
self.trigger('change');
}
@@ -68,6 +88,7 @@
if (this.mode == 'single' || this.mode == 'collection') {
radio_buttons.push({icon: 'fa-folder-o', label : 'List of datasets', value : 'collection' });
this.select_collection = new Ui.Select.View({
+ error_text : hdca_error,
onchange : function() {
self.trigger('change');
}
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/mvc/ui/ui-options.js
--- a/static/scripts/mvc/ui/ui-options.js
+++ b/static/scripts/mvc/ui/ui-options.js
@@ -10,8 +10,8 @@
visible : true,
data : [],
id : Utils.uuid(),
- errorText : 'No data available.',
- waitText : 'Please wait...'
+ error_text : 'No data available.',
+ wait_text : 'Please wait...'
};
// configure options
@@ -153,7 +153,7 @@
*/
wait: function() {
if (this._size() == 0) {
- this._messageShow(this.options.waitText, 'info');
+ this._messageShow(this.options.wait_text, 'info');
this.$options.hide();
}
},
@@ -177,7 +177,7 @@
*/
_refresh: function() {
if (this._size() == 0) {
- this._messageShow(this.options.errorText, 'danger');
+ this._messageShow(this.options.error_text, 'danger');
this.$options.hide();
} else {
this._messageHide();
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/mvc/ui/ui-select-default.js
--- a/static/scripts/mvc/ui/ui-select-default.js
+++ b/static/scripts/mvc/ui/ui-select-default.js
@@ -9,7 +9,7 @@
optionsDefault : {
id : '',
cls : '',
- empty : 'No data available',
+ error_text : 'No data available',
visible : true,
wait : false,
multiple : false,
@@ -247,7 +247,7 @@
this.disable();
// append placeholder
- this.$select.append(this._templateOption({value : 'null', label : this.options.empty}));
+ this.$select.append(this._templateOption({value : 'null', label : this.options.error_text}));
} else {
// enable select field
this.enable();
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["utils/utils","utils/deferred","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(o){console.debug(o);var n=this;var p=parent.Galaxy;if(p&&p.modal){this.modal=p.modal}else{this.modal=new m.Modal.View()}if(p&&p.currUser){this.is_admin=p.currUser.get("is_admin")}else{this.is_admin=false}this.options=o;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);this._buildForm(o)},message:function(n){$(this.container).empty();$(this.container).append(n)},reset:function(){for(var n in this.element_list){this.element_list[n].reset()}},rebuild:function(){this.tree.refresh();console.debug("tools-form::rebuild() - Rebuilding data structures.")},refresh:function(){if(this.is_dynamic){var n=this;this.deferred.reset();this.deferred.execute(function(){n._updateModel()})}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{var p=top.location.href;var q=p.indexOf("?");if(p.indexOf("tool_id=")!=-1&&q!==-1){o+=p.slice(q+1)}}}i.request({type:"GET",url:o,success:function(r){n.options=$.extend(n.options,r);n.model=r;n.inputs=r.inputs;console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(r);n._buildForm()},error:function(r){console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(r)}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(r){if(r.values.length>0&&r.values[0]&&r.values[0].src==="hda"){return n.content.get({id:r.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function q(u){for(var s in n.input_list){var t=n.field_list[s];var r=n.input_list[s];if(r.is_dynamic&&t.wait&&t.unwait){if(u){t.wait()}else{t.unwait()}}}}q(true);var p=this.deferred.register();i.request({type:"GET",url:galaxy_config.root+"api/tools/"+this.options.id+"/build",data:o,success:function(r){n._updateForm(r);q(false);n.deferred.done(p);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(r)},error:function(r){n.deferred.done(p);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(r)}})},_updateForm:function(n){var o=this;this.tree.matchModel(n,function(q,u){var p=o.input_list[q];if(p&&p.options){if(!_.isEqual(p.options,u.options)){p.options=u.options;var v=o.field_list[q];if(v.update){var t=[];switch(p.type){case"data":t=p.options;break;case"drill_down":t=p.options;break;default:for(var s in u.options){var r=u.options[s];if(r.length>2){t.push({label:r[0],value:r[1]})}}}v.update(t);v.trigger("change");console.debug("Updating options for "+q)}}}})},_buildForm:function(p){var o=this;this.field_list={};this.input_list={};this.element_list={};this.model=p;this.inputs=p.inputs;var s=new m.ButtonMenu({icon:"fa-gear",tooltip:"Click to see a list of options."});if(p.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(o.options.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(o.options.biostar_url+"/t/"+o.options.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+o.options.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+o.options.id+"/download"}})}this.section=new l.View(o,{inputs:this.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+this.model.name+"</b> "+this.model.description,cls:"ui-portlet-slim",operations:{menu:s},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){o.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(p.help!=""){this.$el.append(d.help(p.help))}if(p.citations){var r=$("<div/>");var n=new k.ToolCitationCollection();n.tool_id=p.id;var q=new a.CitationListView({el:r,collection:n});q.render();n.fetch();this.$el.append(r)}this.portlet.append(this.section.$el);this.rebuild()}});return{View:b}});
\ No newline at end of file
+define(["utils/utils","utils/deferred","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(o){console.debug(o);var n=this;var p=parent.Galaxy;if(p&&p.modal){this.modal=p.modal}else{this.modal=new m.Modal.View()}if(p&&p.currUser){this.is_admin=p.currUser.get("is_admin")}else{this.is_admin=false}this.options=o;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);this._buildForm(o)},message:function(n){$(this.container).empty();$(this.container).append(n)},reset:function(){for(var n in this.element_list){this.element_list[n].reset()}},rebuild:function(){this.tree.refresh();console.debug("tools-form::rebuild() - Rebuilding data structures.")},refresh:function(){if(this.is_dynamic){var n=this;this.deferred.reset();this.deferred.execute(function(){n._updateModel()})}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{var p=top.location.href;var q=p.indexOf("?");if(p.indexOf("tool_id=")!=-1&&q!==-1){o+=p.slice(q+1)}}}i.request({type:"GET",url:o,success:function(r){n.options=$.extend(n.options,r);n.model=r;n.inputs=r.inputs;console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(r);n._buildForm()},error:function(r){console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(r)}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(r){if(r.values.length>0&&r.values[0]&&r.values[0].src==="hda"){return n.content.get({id:r.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function q(u){for(var s in n.input_list){var t=n.field_list[s];var r=n.input_list[s];if(r.is_dynamic&&t.wait&&t.unwait){if(u){t.wait()}else{t.unwait()}}}}q(true);var p=this.deferred.register();i.request({type:"GET",url:galaxy_config.root+"api/tools/"+this.options.id+"/build",data:o,success:function(r){n._updateForm(r);q(false);n.deferred.done(p);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(r)},error:function(r){n.deferred.done(p);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(r)}})},_updateForm:function(n){var o=this;this.tree.matchModel(n,function(q,u){var p=o.input_list[q];if(p&&p.options){if(!_.isEqual(p.options,u.options)){p.options=u.options;var v=o.field_list[q];if(v.update){var t=[];switch(p.type){case"data":t=p.options;break;case"drill_down":t=p.options;break;default:for(var s in u.options){var r=u.options[s];if(r.length>2){t.push({label:r[0],value:r[1]})}}}v.update(t);v.trigger("change");console.debug("Updating options for "+q)}}}})},_buildForm:function(p){var o=this;this.field_list={};this.input_list={};this.element_list={};this.model=p;this.inputs=p.inputs;var s=new m.ButtonMenu({icon:"fa-gear",tooltip:"Click to see a list of options."});if(p.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(o.options.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(o.options.biostar_url+"/t/"+o.options.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+o.options.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+o.options.id+"/download"}})}this.section=new l.View(o,{inputs:this.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+this.model.name+"</b> "+this.model.description,cls:"ui-portlet-slim",operations:{menu:s},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+o.model.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){o.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(p.help!=""){this.$el.append(d.help(p.help))}if(p.citations){var r=$("<div/>");var n=new k.ToolCitationCollection();n.tool_id=p.id;var q=new a.CitationListView({el:r,collection:n});q.render();n.fetch();this.$el.append(r)}this.portlet.append(this.section.$el);this.rebuild()}});return{View:b}});
\ No newline at end of file
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.error_text="Referenced dataset contains no suitable columns";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/packed/mvc/tools/tools-select-content.js
--- a/static/scripts/packed/mvc/tools/tools-select-content.js
+++ b/static/scripts/packed/mvc/tools/tools-select-content.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(k,g){this.app=k;this.options=g;var f=this;this.setElement("<div/>");this.list={};var j=[];if(g.type=="data_collection"){this.mode="collection"}else{if(g.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};if(this.mode=="single"){j.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){j.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,onchange:function(){f.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){j.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({onchange:function(){f.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:j,onchange:function(i){f.current=i;f.refresh();f.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var h in this.list){this.$el.append(this.list[h].field.$el)}this.$el.append(this.$batch);this.update(g.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(g.onchange){g.onchange(f.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement("<div/>");this.list={};var m=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=o.extensions.toString();if(j){j=j.replace(",",", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available";if(j){h="No dataset of type "+j+" available."}var l="No dataset list available";if(j){l="No dataset list of type "+j+" available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({error_text:l,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/packed/mvc/ui/ui-options.js
--- a/static/scripts/packed/mvc/ui/ui-options.js
+++ b/static/scripts/packed/mvc/ui/ui-options.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),errorText:"No data available.",waitText:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement("<div/>");this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){var g=this.value();if(!(g instanceof Array)){g=[g]}for(var f in g){if([null,"null",undefined].indexOf(g[f])>-1){return false}}return true},wait:function(){if(this._size()==0){this._messageShow(this.options.waitText,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.errorText,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"null"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(g){var f='<label class="btn btn-default">';if(g.icon){f+='<i class="fa '+g.icon+'"/>'}f+='<input type="radio" name="'+this.options.id+'" value="'+g.value+'">'+g.label+"</label>";return f},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
\ No newline at end of file
+define(["utils/utils"],function(b){var a=Backbone.View.extend({initialize:function(g){this.optionsDefault={visible:true,data:[],id:b.uuid(),error_text:"No data available.",wait_text:"Please wait..."};this.options=b.merge(g,this.optionsDefault);this.setElement("<div/>");this.$message=$("<div/>");this.$options=$(this._template(g));this.$el.append(this.$message);this.$el.append(this.$options);if(!this.options.visible){this.$el.hide()}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}var f=this;this.on("change",function(){f._change()})},update:function(g){var j=this._getValue();this.$options.empty();if(this._templateOptions){this.$options.append(this._templateOptions(g))}else{for(var h in g){var i=$(this._templateOption(g[h]));i.addClass("ui-option");this.$options.append(i)}}var f=this;this.$el.find("input").on("change",function(){f.value(f._getValue());f._change()});this._refresh();this.value(j)},value:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}this.$el.find("input").prop("checked",false);for(var f in g){this.$el.find('input[value="'+g[f]+'"]').first().prop("checked",true)}}return this._getValue()},exists:function(g){if(g!==undefined){if(!(g instanceof Array)){g=[g]}for(var f in g){if(this.$el.find('input[value="'+g[f]+'"]').length>0){return true}}}return false},first:function(){var f=this.$el.find("input");if(f.length>0){return f.val()}else{return undefined}},validate:function(){var g=this.value();if(!(g instanceof Array)){g=[g]}for(var f in g){if([null,"null",undefined].indexOf(g[f])>-1){return false}}return true},wait:function(){if(this._size()==0){this._messageShow(this.options.wait_text,"info");this.$options.hide()}},unwait:function(){this._messageHide();this._refresh()},_change:function(){if(this.options.onchange){this.options.onchange(this._getValue())}},_refresh:function(){if(this._size()==0){this._messageShow(this.options.error_text,"danger");this.$options.hide()}else{this._messageHide();this.$options.css("display","inline-block")}},_getValue:function(){var g=this.$el.find(":checked");if(g.length==0){return"null"}if(this.options.multiple){var f=[];g.each(function(){f.push($(this).val())});return f}else{return g.val()}},_size:function(){return this.$el.find(".ui-option").length},_messageShow:function(g,f){this.$message.show();this.$message.removeClass();this.$message.addClass("ui-message alert alert-"+f);this.$message.html(g)},_messageHide:function(){this.$message.hide()},_template:function(){return'<div class="ui-options"/>'}});var d={};d.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="radio" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var c={};c.View=a.extend({initialize:function(f){f.multiple=true;a.prototype.initialize.call(this,f)},_templateOption:function(f){return'<div><input type="checkbox" name="'+this.options.id+'" value="'+f.value+'"/>'+f.label+"<br></div>"}});var e={};e.View=a.extend({initialize:function(f){a.prototype.initialize.call(this,f)},value:function(f){if(f!==undefined){this.$el.find("input").prop("checked",false);this.$el.find("label").removeClass("active");this.$el.find('[value="'+f+'"]').prop("checked",true).closest("label").addClass("active")}return this._getValue()},_templateOption:function(g){var f='<label class="btn btn-default">';if(g.icon){f+='<i class="fa '+g.icon+'"/>'}f+='<input type="radio" name="'+this.options.id+'" value="'+g.value+'">'+g.label+"</label>";return f},_template:function(){return'<div class="btn-group ui-radiobutton" data-toggle="buttons"/>'}});return{Base:a,Radio:d,RadioButton:e,Checkbox:c}});
\ No newline at end of file
diff -r 77f9f54744d480948aec2f0662657139f35f87fb -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c static/scripts/packed/mvc/ui/ui-select-default.js
--- a/static/scripts/packed/mvc/ui/ui-select-default.js
+++ b/static/scripts/packed/mvc/ui/ui-select-default.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{id:"",cls:"",empty:"No data available",visible:true,wait:false,multiple:false,searchable:false},initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$select=this.$el.find(".select");this.$icon=this.$el.find(".icon");this.$button=this.$el.find(".button");if(this.options.multiple){this.$select.prop("multiple",true);this.$select.addClass("ui-select-multiple");this.$icon.remove()}else{this.$el.addClass("ui-select")}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}if(!this.options.visible){this.hide()}if(this.options.wait){this.wait()}else{this.show()}var c=this;this.$select.on("change",function(){c._change()});this.on("change",function(){c._change()})},value:function(c){if(c!==undefined){this.$select.val(c);if(this.$select.select2){this.$select.select2("val",c)}}return this.$select.val()},first:function(){var c=this.$select.find("option");if(c.length>0){return c.val()}else{return undefined}},validate:function(){var d=this.value();if(!(d instanceof Array)){d=[d]}for(var c in d){if([null,"null",undefined].indexOf(d[c])>-1){return false}}return true},text:function(){return this.$select.find("option:selected").text()},show:function(){this.unwait();this.$select.show();this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-spinner fa-spin")},unwait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-caret-down")},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",false)},disable:function(){this.$select.prop("disabled",true)},add:function(c){this.$select.append(this._templateOption(c));this._refresh()},del:function(c){this.$select.find("option[value="+c+"]").remove();this.$select.trigger("change");this._refresh()},update:function(c){var e=this.$select.val();this.$select.find("option").remove();for(var d in c){this.$select.append(this._templateOption(c[d]))}this._refresh();this.$select.val(e);if(!this.$select.val()){this.$select.val(this.first())}if(this.options.searchable){this.$button.hide();this.$select.select2("destroy");this.$select.select2()}},setOnChange:function(c){this.options.onchange=c},exists:function(c){return this.$select.find('option[value="'+c+'"]').length>0},_change:function(){if(this.options.onchange){this.options.onchange(this.$select.val())}},_refresh:function(){this.$select.find("option[value=null]").remove();var c=this.$select.find("option").length;if(c==0){this.disable();this.$select.append(this._templateOption({value:"null",label:this.options.empty}))}else{this.enable()}},_templateOption:function(c){return'<option value="'+c.value+'">'+c.label+"</option>"},_template:function(c){return'<div id="'+c.id+'"><select id="select" class="select '+c.cls+" "+c.id+'"></select><div class="button"><i class="icon"/></div></div>'}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{id:"",cls:"",error_text:"No data available",visible:true,wait:false,multiple:false,searchable:false},initialize:function(d){this.options=a.merge(d,this.optionsDefault);this.setElement(this._template(this.options));this.$select=this.$el.find(".select");this.$icon=this.$el.find(".icon");this.$button=this.$el.find(".button");if(this.options.multiple){this.$select.prop("multiple",true);this.$select.addClass("ui-select-multiple");this.$icon.remove()}else{this.$el.addClass("ui-select")}this.update(this.options.data);if(this.options.value!==undefined){this.value(this.options.value)}if(!this.options.visible){this.hide()}if(this.options.wait){this.wait()}else{this.show()}var c=this;this.$select.on("change",function(){c._change()});this.on("change",function(){c._change()})},value:function(c){if(c!==undefined){this.$select.val(c);if(this.$select.select2){this.$select.select2("val",c)}}return this.$select.val()},first:function(){var c=this.$select.find("option");if(c.length>0){return c.val()}else{return undefined}},validate:function(){var d=this.value();if(!(d instanceof Array)){d=[d]}for(var c in d){if([null,"null",undefined].indexOf(d[c])>-1){return false}}return true},text:function(){return this.$select.find("option:selected").text()},show:function(){this.unwait();this.$select.show();this.$el.show()},hide:function(){this.$el.hide()},wait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-spinner fa-spin")},unwait:function(){this.$icon.removeClass();this.$icon.addClass("fa fa-caret-down")},disabled:function(){return this.$select.is(":disabled")},enable:function(){this.$select.prop("disabled",false)},disable:function(){this.$select.prop("disabled",true)},add:function(c){this.$select.append(this._templateOption(c));this._refresh()},del:function(c){this.$select.find("option[value="+c+"]").remove();this.$select.trigger("change");this._refresh()},update:function(c){var e=this.$select.val();this.$select.find("option").remove();for(var d in c){this.$select.append(this._templateOption(c[d]))}this._refresh();this.$select.val(e);if(!this.$select.val()){this.$select.val(this.first())}if(this.options.searchable){this.$button.hide();this.$select.select2("destroy");this.$select.select2()}},setOnChange:function(c){this.options.onchange=c},exists:function(c){return this.$select.find('option[value="'+c+'"]').length>0},_change:function(){if(this.options.onchange){this.options.onchange(this.$select.val())}},_refresh:function(){this.$select.find("option[value=null]").remove();var c=this.$select.find("option").length;if(c==0){this.disable();this.$select.append(this._templateOption({value:"null",label:this.options.error_text}))}else{this.enable()}},_templateOption:function(c){return'<option value="'+c.value+'">'+c.label+"</option>"},_template:function(c){return'<div id="'+c.id+'"><select id="select" class="select '+c.cls+" "+c.id+'"></select><div class="button"><i class="icon"/></div></div>'}});return{View:b}});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/7b1b9a075317/
Changeset: 7b1b9a075317
Branch: next-stable
User: guerler
Date: 2014-12-04 16:53:22+00:00
Summary: ToolForm: Update error message
Affected #: 3 files
diff -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 client/galaxy/scripts/mvc/tools/tools-select-content.js
--- a/client/galaxy/scripts/mvc/tools/tools-select-content.js
+++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js
@@ -41,16 +41,16 @@
extensions = extensions.replace(',', ', ');
var pos = extensions.lastIndexOf(', ');
if (pos != -1) {
- extensions = extensions.substr(0, pos) + " or " + extensions.substr(pos+1);
+ extensions = extensions.substr(0, pos) + ' or ' + extensions.substr(pos+1);
}
}
- var hda_error = 'No dataset available';
+ var hda_error = 'No dataset available.';
if (extensions) {
- hda_error = 'No dataset of type ' + extensions + ' available.';
+ hda_error = 'No ' + extensions + ' dataset available.';
}
- var hdca_error = 'No dataset list available';
+ var hdca_error = 'No dataset list available.';
if (extensions) {
- hdca_error = 'No dataset list of type ' + extensions + ' available.';
+ hdca_error = 'No ' + extensions + ' dataset list available.';
}
// add single dataset selector
diff -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 static/scripts/mvc/tools/tools-select-content.js
--- a/static/scripts/mvc/tools/tools-select-content.js
+++ b/static/scripts/mvc/tools/tools-select-content.js
@@ -41,16 +41,16 @@
extensions = extensions.replace(',', ', ');
var pos = extensions.lastIndexOf(', ');
if (pos != -1) {
- extensions = extensions.substr(0, pos) + " or " + extensions.substr(pos+1);
+ extensions = extensions.substr(0, pos) + ' or ' + extensions.substr(pos+1);
}
}
- var hda_error = 'No dataset available';
+ var hda_error = 'No dataset available.';
if (extensions) {
- hda_error = 'No dataset of type ' + extensions + ' available.';
+ hda_error = 'No ' + extensions + ' dataset available.';
}
- var hdca_error = 'No dataset list available';
+ var hdca_error = 'No dataset list available.';
if (extensions) {
- hdca_error = 'No dataset list of type ' + extensions + ' available.';
+ hdca_error = 'No ' + extensions + ' dataset list available.';
}
// add single dataset selector
diff -r 97f0146a1ff06851a999e0a78a3cb512a4cc644c -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 static/scripts/packed/mvc/tools/tools-select-content.js
--- a/static/scripts/packed/mvc/tools/tools-select-content.js
+++ b/static/scripts/packed/mvc/tools/tools-select-content.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement("<div/>");this.list={};var m=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=o.extensions.toString();if(j){j=j.replace(",",", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available";if(j){h="No dataset of type "+j+" available."}var l="No dataset list available";if(j){l="No dataset list of type "+j+" available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({error_text:l,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(f,o){this.app=f;this.options=o;var n=this;this.setElement("<div/>");this.list={};var m=[];if(o.type=="data_collection"){this.mode="collection"}else{if(o.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var j=o.extensions.toString();if(j){j=j.replace(",",", ");var k=j.lastIndexOf(", ");if(k!=-1){j=j.substr(0,k)+" or "+j.substr(k+1)}}var h="No dataset available.";if(j){h="No "+j+" dataset available."}var l="No dataset list available.";if(j){l="No "+j+" dataset list available."}if(this.mode=="single"){m.push({icon:"fa-file-o",label:"Single dataset",value:"single"});this.select_single=new e.Select.View({error_text:h,onchange:function(){n.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",label:"Multiple datasets",value:"multiple"});this.select_multiple=new e.Select.View({multiple:true,error_text:h,onchange:function(){n.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="collection"){m.push({icon:"fa-folder-o",label:"List of datasets",value:"collection"});this.select_collection=new e.Select.View({error_text:l,onchange:function(){n.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){n.current=i;n.refresh();n.trigger("change")}});this.$batch=$(a.batchMode());if(_.size(this.list)>1){this.$el.append(c.wrap(this.button_type.$el))}for(var g in this.list){this.$el.append(this.list[g].field.$el)}this.$el.append(this.$batch);this.update(o.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(o.onchange){o.onchange(n.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){var l=[];for(var j in g.hda){var k=g.hda[j];l.push({label:k.hid+": "+k.name,value:k.id})}var f=[];for(var j in g.hdca){var h=g.hdca[j];f.push({label:h.hid+": "+h.name,value:h.id})}this.select_single&&this.select_single.update(l);this.select_multiple&&this.select_multiple.update(l);this.select_collection&&this.select_collection.update(f);this.app.content.add(g)},value:function(m){if(m&&m.values){try{var l=[];for(var h in m.values){l.push(m.values[h].id)}if(m&&m.values.length>0&&m.values[0].src=="hcda"){this.current="collection";this.select_collection.value(l[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(l)}else{this.current="single";this.select_single.value(l[0])}}this.refresh();var g=this._select();if(!g.validate()){g.value(g.first())}}catch(k){console.debug("tools-select-content::value() - Skipped.")}}var j=this._select().value();if(!(j instanceof Array)){j=[j]}var f={batch:this.mode=="single"&&this.current!="single",values:[]};for(var h in j){f.values.push({id:j[h],src:this.list[this.current].type})}return f},validate:function(){return this._select().validate()},refresh:function(){for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this.mode=="single"&&this.current!="single"){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field}});return{View:d}});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/89bfc7488769/
Changeset: 89bfc7488769
Branch: next-stable
User: guerler
Date: 2014-12-04 16:59:21+00:00
Summary: ToolForm: Update error message for missing columns
Affected #: 3 files
diff -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -314,7 +314,7 @@
// data column
case 'data_column':
- input_def.error_text = 'Referenced dataset contains no suitable columns';
+ input_def.error_text = 'Referenced dataset has no matching columns.';
field = this._fieldSelect(input_def);
break;
diff -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -314,7 +314,7 @@
// data column
case 'data_column':
- input_def.error_text = 'Referenced dataset contains no suitable columns';
+ input_def.error_text = 'Referenced dataset has no matching columns.';
field = this._fieldSelect(input_def);
break;
diff -r 7b1b9a075317a5c87b4be21a3ef4da6ef38f6420 -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.error_text="Referenced dataset contains no suitable columns";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.error_text="Referenced dataset has no matching columns.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
https://bitbucket.org/galaxy/galaxy-central/commits/9ddc3efa9c32/
Changeset: 9ddc3efa9c32
Branch: next-stable
User: guerler
Date: 2014-12-04 17:01:34+00:00
Summary: ToolForm: Update error message again
Affected #: 3 files
diff -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 client/galaxy/scripts/mvc/tools/tools-section.js
--- a/client/galaxy/scripts/mvc/tools/tools-section.js
+++ b/client/galaxy/scripts/mvc/tools/tools-section.js
@@ -314,7 +314,7 @@
// data column
case 'data_column':
- input_def.error_text = 'Referenced dataset has no matching columns.';
+ input_def.error_text = 'Missing columns in referenced dataset.';
field = this._fieldSelect(input_def);
break;
diff -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 static/scripts/mvc/tools/tools-section.js
--- a/static/scripts/mvc/tools/tools-section.js
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -314,7 +314,7 @@
// data column
case 'data_column':
- input_def.error_text = 'Referenced dataset has no matching columns.';
+ input_def.error_text = 'Missing columns in referenced dataset.';
field = this._fieldSelect(input_def);
break;
diff -r 89bfc74887698d8433b5a4c38aa8e33087f4cb2c -r 9ddc3efa9c3245a7dfd24680bdb816f3d4852094 static/scripts/packed/mvc/tools/tools-section.js
--- a/static/scripts/packed/mvc/tools/tools-section.js
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -1,1 +1,1 @@
-define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.error_text="Referenced dataset has no matching columns.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
+define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/tools/tools-repeat","mvc/tools/tools-select-content","mvc/tools/tools-input"],function(d,b,g,c,a,e){var f=Backbone.View.extend({initialize:function(i,h){this.app=i;this.inputs=h.inputs;h.cls_tr="section-row";this.table=new b.View(h);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var h in this.inputs){this._add(this.inputs[h])}},_add:function(j){var i=this;var h=jQuery.extend(true,{},j);h.id=j.id=d.uuid();this.app.input_list[h.id]=h;var k=h.type;switch(k){case"conditional":this._addConditional(h);break;case"repeat":this._addRepeat(h);break;default:this._addRow(h)}},_addConditional:function(h){var j=this;h.test_param.id=h.id;var m=this._addRow(h.test_param);m.options.onchange=function(t){var p=j.app.tree.matchCase(h,t);for(var r in h.cases){var w=h.cases[r];var u=h.id+"-section-"+r;var o=j.table.get(u);var v=false;for(var q in w.inputs){var s=w.inputs[q].type;if(s&&s!=="hidden"){v=true;break}}if(r==p&&v){o.fadeIn("fast")}else{o.hide()}}j.app.refresh()};for(var l in h.cases){var k=h.id+"-section-"+l;var n=new f(this.app,{inputs:h.cases[l].inputs,cls:"ui-table-plain"});n.$el.addClass("ui-table-form-section");this.table.add(n.$el);this.table.append(k)}m.trigger("change")},_addRepeat:function(o){var r=this;var p=0;function m(i,t){var s=o.id+"-section-"+(p++);var u=null;if(t){u=function(){k.del(s);k.retitle(o.title);r.app.rebuild();r.app.refresh()}}var v=new f(r.app,{inputs:i,cls:"ui-table-plain"});k.add({id:s,title:o.title,$el:v.$el,ondel:u});k.retitle(o.title)}var k=new c.View({title_new:o.title,max:o.max,onnew:function(){m(o.inputs,true);r.app.rebuild();r.app.refresh()}});var h=o.min;var q=_.size(o.cache);for(var l=0;l<Math.max(q,h);l++){var n=null;if(l<q){n=o.cache[l]}else{n=o.inputs}m(n,l>=h)}var j=new e(this.app,{label:o.title,help:o.help,field:k});j.$el.addClass("ui-table-form-section");this.table.add(j.$el);this.table.append(o.id)},_addRow:function(h){var k=h.id;var i=this._createField(h);if(h.is_dynamic){this.app.is_dynamic=true}this.app.field_list[k]=i;var j=new e(this.app,{label:h.label,optional:h.optional,help:h.help,field:i});this.app.element_list[k]=j;this.table.add(j.$el);this.table.append(k);return i},_createField:function(h){var i=null;switch(h.type){case"text":i=this._fieldText(h);break;case"select":i=this._fieldSelect(h);break;case"data":i=this._fieldData(h);break;case"data_column":h.error_text="Missing columns in referenced dataset.";i=this._fieldSelect(h);break;case"hidden":i=this._fieldHidden(h);break;case"integer":i=this._fieldSlider(h);break;case"float":i=this._fieldSlider(h);break;case"boolean":i=this._fieldBoolean(h);break;case"genomebuild":h.searchable=true;i=this._fieldSelect(h);break;case"drill_down":i=this._fieldDrilldown(h);break;case"baseurl":i=this._fieldHidden(h);break;default:this.app.incompatible=true;if(h.options){i=this._fieldSelect(h)}else{i=this._fieldText(h)}console.debug("tools-form::_addRow() : Auto matched field type ("+h.type+").")}if(h.value!==undefined){i.value(h.value)}return i},_fieldData:function(h){var i=this;return new a.View(this.app,{id:"field-"+h.id,extensions:h.extensions,multiple:h.multiple,type:h.type,data:h.options,onchange:function(){i.app.refresh()}})},_fieldSelect:function(h){var k=[];for(var l in h.options){var m=h.options[l];k.push({label:m[0],value:m[1]})}var n=g.Select;switch(h.display){case"checkboxes":n=g.Checkbox;break;case"radio":n=g.Radio;break}var j=this;return new n.View({id:"field-"+h.id,data:k,error_text:h.error_text||"No options available",multiple:h.multiple,searchable:h.searchable,onchange:function(){j.app.refresh()}})},_fieldDrilldown:function(h){var i=this;return new g.Drilldown.View({id:"field-"+h.id,data:h.options,display:h.display,onchange:function(){i.app.refresh()}})},_fieldText:function(h){var i=this;return new g.Input({id:"field-"+h.id,area:h.area,onchange:function(){i.app.refresh()}})},_fieldSlider:function(h){return new g.Slider.View({id:"field-"+h.id,precise:h.type=="float",min:h.min,max:h.max})},_fieldHidden:function(h){return new g.Hidden({id:"field-"+h.id})},_fieldBoolean:function(h){return new g.RadioButton.View({id:"field-"+h.id,data:[{label:"Yes",value:"true"},{label:"No",value:"false"}]})}});return{View:f}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Update tag latest_2014.10.06 for changeset 8e45b1cefba1
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/885f940bff64/
Changeset: 885f940bff64
Branch: stable
User: natefoo
Date: 2014-12-05 21:00:16+00:00
Summary: Update tag latest_2014.10.06 for changeset 8e45b1cefba1
Affected #: 1 file
diff -r 8e45b1cefba16727d4d3a7d0dceaaaf1ef400a0c -r 885f940bff64bbb6769fd31b21b0c73f4bfe1642 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -20,4 +20,4 @@
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
548ab24667d6206780237bd807f7d857a484c461 latest_2014.08.11
2092948937ac30ef82f71463a235c66d34987088 release_2014.10.06
-9c482e1d9b3cfdb2936b3f230d434c1f27898eff latest_2014.10.06
+8e45b1cefba16727d4d3a7d0dceaaaf1ef400a0c latest_2014.10.06
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d2a8b1c249c8/
Changeset: d2a8b1c249c8
Branch: disable_mobile
User: martenson
Date: 2014-12-03 16:57:20+00:00
Summary: disable the mobile version of the site; redirect to index from every used URL
Affected #: 1 file
diff -r 795336f22d8b94b86256b1d4738ee1bf24e18b57 -r d2a8b1c249c823fa3dd56be34158607d3a65680f lib/galaxy/webapps/galaxy/controllers/mobile.py
--- a/lib/galaxy/webapps/galaxy/controllers/mobile.py
+++ b/lib/galaxy/webapps/galaxy/controllers/mobile.py
@@ -1,60 +1,71 @@
+from galaxy import web
from galaxy.web.base.controller import *
+
class Mobile( BaseUIController ):
+
@web.expose
def index( self, trans, **kwargs ):
- return trans.fill_template( "mobile/index.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/index.mako" )
@web.expose
def history_list( self, trans ):
- return trans.fill_template( "mobile/history/list.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/history/list.mako" )
@web.expose
def history_detail( self, trans, id ):
- history = trans.sa_session.query( trans.app.model.History ).get( id )
- assert history.user == trans.user
- return trans.fill_template( "mobile/history/detail.mako", history=history )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # history = trans.sa_session.query( trans.app.model.History ).get( id )
+ # assert history.user == trans.user
+ # return trans.fill_template( "mobile/history/detail.mako", history=history )
@web.expose
def dataset_detail( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
@web.expose
def dataset_peek( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
@web.expose
def settings( self, trans, email=None, password=None ):
- message = None
- if email is not None and password is not None:
- if email == "":
- self.__logout( trans )
- message = "Logged out"
- else:
- error = self.__login( trans, email, password )
- message = error or "Login changed"
- return trans.fill_template( "mobile/settings.mako", message=message )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # message = None
+ # if email is not None and password is not None:
+ # if email == "":
+ # self.__logout( trans )
+ # message = "Logged out"
+ # else:
+ # error = self.__login( trans, email, password )
+ # message = error or "Login changed"
+ # return trans.fill_template( "mobile/settings.mako", message=message )
def __logout( self, trans ):
- trans.log_event( "User logged out" )
- trans.handle_user_logout()
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # trans.log_event( "User logged out" )
+ # trans.handle_user_logout()
def __login( self, trans, email="", password="" ):
- error = password_error = None
- user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
- if not user:
- error = "No such user (please note that login is case sensitive)"
- elif user.deleted:
- error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
- elif user.external:
- error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
- elif not user.check_password( password ):
- error = "Invalid password"
- else:
- trans.handle_user_login( user )
- trans.log_event( "User logged in" )
- return error
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # error = password_error = None
+ # user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
+ # if not user:
+ # error = "No such user (please note that login is case sensitive)"
+ # elif user.deleted:
+ # error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
+ # elif user.external:
+ # error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
+ # elif not user.check_password( password ):
+ # error = "Invalid password"
+ # else:
+ # trans.handle_user_login( user )
+ # trans.log_event( "User logged in" )
+ # return error
https://bitbucket.org/galaxy/galaxy-central/commits/b65f60a842c1/
Changeset: b65f60a842c1
Branch: mako_escape_requests
User: martenson
Date: 2014-12-04 16:56:46+00:00
Summary: Closed branch mako_escape_requests
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/2ee22028d4de/
Changeset: 2ee22028d4de
Branch: disable_mobile
User: martenson
Date: 2014-12-04 16:57:19+00:00
Summary: Closed branch disable_mobile
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/8f76a6abc5d7/
Changeset: 8f76a6abc5d7
Branch: next-stable
User: martenson
Date: 2014-12-05 20:11:16+00:00
Summary: add API endpoint to un/mark library folder as deleted
Affected #: 3 files
diff -r c1d4e82df5cbf8a6d551221a0d4013d658ad4748 -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 lib/galaxy/managers/folders.py
--- a/lib/galaxy/managers/folders.py
+++ b/lib/galaxy/managers/folders.py
@@ -16,14 +16,14 @@
Interface/service object for interacting with folders.
"""
- def get( self, trans, decoded_folder_id, check_ownership=False, check_accessible=True):
+ def get( self, trans, decoded_folder_id, check_manageable=False, check_accessible=True):
"""
Get the folder from the DB.
:param decoded_folder_id: decoded folder id
:type decoded_folder_id: int
- :param check_ownership: flag whether the check that user is owner
- :type check_ownership: bool
+ :param check_manageable: flag whether the check that user can manage item
+ :type check_manageable: bool
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
@@ -38,17 +38,17 @@
raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.' )
except Exception, e:
raise exceptions.InternalServerError( 'Error loading from the database.' + str( e ) )
- folder = self.secure( trans, folder, check_ownership, check_accessible )
+ folder = self.secure( trans, folder, check_manageable, check_accessible )
return folder
- def secure( self, trans, folder, check_ownership=True, check_accessible=True ):
+ def secure( self, trans, folder, check_manageable=True, check_accessible=True ):
"""
- Check if (a) user owns folder or (b) folder is accessible to user.
+ Check if (a) user can manage folder or (b) folder is accessible to user.
:param folder: folder item
:type folder: LibraryFolder
- :param check_ownership: flag whether the check that user is owner
- :type check_ownership: bool
+ :param check_manageable: flag whether to check that user can manage item
+ :type check_manageable: bool
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
@@ -58,23 +58,26 @@
# all folders are accessible to an admin
if trans.user_is_admin():
return folder
- if check_ownership:
- folder = self.check_ownership( trans, folder )
+ if check_manageable:
+ folder = self.check_manageable( trans, folder )
if check_accessible:
folder = self.check_accessible( trans, folder )
return folder
- def check_ownership( self, trans, folder ):
+ def check_manageable( self, trans, folder ):
"""
- Check whether the user is owner of the folder.
+ Check whether the user can manage the folder.
:returns: the original folder
:rtype: LibraryFolder
+
+ :raises: AuthenticationRequired, InsufficientPermissionsException
"""
if not trans.user:
- raise exceptions.AuthenticationRequired( "Must be logged in to manage Galaxy items", type='error' )
- if folder.user != trans.user:
- raise exceptions.ItemOwnershipException( "Folder is not owned by the current user", type='error' )
+ raise exceptions.AuthenticationRequired( "Must be logged in to manage Galaxy items.", type='error' )
+ current_user_roles = trans.get_current_user_roles()
+ if not trans.app.security_agent.can_manage_library_item( current_user_roles, folder ):
+ raise exceptions.InsufficientPermissionsException( "You don't have permissions to manage this folder.", type='error' )
else:
return folder
@@ -135,6 +138,22 @@
trans.app.security_agent.copy_library_permissions( trans, parent_folder, new_folder )
return new_folder
+ def delete( self, trans, folder, undelete=False ):
+ """
+ Mark given folder deleted/undeleted based on the flag.
+
+ :raises: ItemAccessibilityException
+ """
+ if not trans.user_is_admin():
+ folder = self.check_manageable( trans, folder )
+ if undelete:
+ folder.deleted = False
+ else:
+ folder.deleted = True
+ trans.sa_session.add( folder )
+ trans.sa_session.flush()
+ return folder
+
def get_current_roles( self, trans, folder ):
"""
Find all roles currently connected to relevant permissions
diff -r c1d4e82df5cbf8a6d551221a0d4013d658ad4748 -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2192,7 +2192,7 @@
return roles
class LibraryFolder( object, Dictifiable, HasName ):
- dict_element_visible_keys = ( 'id', 'parent_id', 'name', 'description', 'item_count', 'genome_build', 'update_time' )
+ dict_element_visible_keys = ( 'id', 'parent_id', 'name', 'description', 'item_count', 'genome_build', 'update_time', 'deleted' )
def __init__( self, name=None, description=None, item_count=0, order_id=None ):
self.name = name or "Unnamed folder"
self.description = description
diff -r c1d4e82df5cbf8a6d551221a0d4013d658ad4748 -r 8f76a6abc5d7d5c98b6c148c4cfe75cc1c159e90 lib/galaxy/webapps/galaxy/api/folders.py
--- a/lib/galaxy/webapps/galaxy/api/folders.py
+++ b/lib/galaxy/webapps/galaxy/api/folders.py
@@ -44,7 +44,7 @@
:rtype: dict
"""
folder_id = self.folder_manager.cut_and_decode( trans, id )
- folder = self.folder_manager.get( trans, folder_id, check_ownership=False, check_accessible=True )
+ folder = self.folder_manager.get( trans, folder_id, check_manageable=False, check_accessible=True )
return_dict = self.folder_manager.get_folder_dict( trans, folder )
return return_dict
@@ -229,6 +229,32 @@
'Allowed values are: "set_permissions"' )
return self.folder_manager.get_current_roles( trans, folder )
+ @expose_api
+ def delete( self, trans, id, **kwd ):
+ """
+ delete( self, trans, id, **kwd )
+ * DELETE /api/folders/{id}
+ marks the folder with the given ``id`` as `deleted` (or removes the `deleted` mark if the `undelete` param is true)
+
+ .. note:: Currently, only admin users can un/delete folders.
+
+ :param id: the encoded id of the folder to un/delete
+ :type id: an encoded id string
+
+ :param undelete: (optional) flag specifying whether the item should be deleted or undeleted, defaults to false:
+ :type undelete: bool
+
+ :returns: detailed folder information
+ :rtype: dictionary
+
+ :raises: ItemAccessibilityException, MalformedId, ObjectNotFound
+ """
+ folder = self.folder_manager.get( trans, self.folder_manager.cut_and_decode( trans, id ), True )
+ undelete = util.string_as_bool( kwd.get( 'undelete', False ) )
+ folder = self.folder_manager.delete( trans, folder, undelete )
+ folder_dict = self.folder_manager.get_folder_dict( trans, folder )
+ return folder_dict
+
@web.expose_api
def update( self, trans, id, library_id, payload, **kwd ):
"""
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3065d710f638/
Changeset: 3065d710f638
Branch: admin_cleanup_datasets_fix
User: dannon
Date: 2014-12-05 19:23:07+00:00
Summary: Branch prune.
Affected #: 0 files
https://bitbucket.org/galaxy/galaxy-central/commits/a89b1dca8dd5/
Changeset: a89b1dca8dd5
Branch: mako_escape_requests
User: dannon
Date: 2014-12-05 19:23:15+00:00
Summary: Branch prune.
Affected #: 0 files
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Merged in martenson/galaxy-central-marten/stable (pull request #592)
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8e45b1cefba1/
Changeset: 8e45b1cefba1
Branch: stable
User: jmchilton
Date: 2014-12-05 16:57:27+00:00
Summary: Merged in martenson/galaxy-central-marten/stable (pull request #592)
[STABLE] disable mobile version of the website
Affected #: 1 file
diff -r f76fb3c40d55adf4f84acfdf26194d323f860df6 -r 8e45b1cefba16727d4d3a7d0dceaaaf1ef400a0c lib/galaxy/webapps/galaxy/controllers/mobile.py
--- a/lib/galaxy/webapps/galaxy/controllers/mobile.py
+++ b/lib/galaxy/webapps/galaxy/controllers/mobile.py
@@ -1,60 +1,71 @@
+from galaxy import web
from galaxy.web.base.controller import *
+
class Mobile( BaseUIController ):
+
@web.expose
def index( self, trans, **kwargs ):
- return trans.fill_template( "mobile/index.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/index.mako" )
@web.expose
def history_list( self, trans ):
- return trans.fill_template( "mobile/history/list.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/history/list.mako" )
@web.expose
def history_detail( self, trans, id ):
- history = trans.sa_session.query( trans.app.model.History ).get( id )
- assert history.user == trans.user
- return trans.fill_template( "mobile/history/detail.mako", history=history )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # history = trans.sa_session.query( trans.app.model.History ).get( id )
+ # assert history.user == trans.user
+ # return trans.fill_template( "mobile/history/detail.mako", history=history )
@web.expose
def dataset_detail( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
@web.expose
def dataset_peek( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
@web.expose
def settings( self, trans, email=None, password=None ):
- message = None
- if email is not None and password is not None:
- if email == "":
- self.__logout( trans )
- message = "Logged out"
- else:
- error = self.__login( trans, email, password )
- message = error or "Login changed"
- return trans.fill_template( "mobile/settings.mako", message=message )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # message = None
+ # if email is not None and password is not None:
+ # if email == "":
+ # self.__logout( trans )
+ # message = "Logged out"
+ # else:
+ # error = self.__login( trans, email, password )
+ # message = error or "Login changed"
+ # return trans.fill_template( "mobile/settings.mako", message=message )
def __logout( self, trans ):
- trans.log_event( "User logged out" )
- trans.handle_user_logout()
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # trans.log_event( "User logged out" )
+ # trans.handle_user_logout()
def __login( self, trans, email="", password="" ):
- error = password_error = None
- user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
- if not user:
- error = "No such user (please note that login is case sensitive)"
- elif user.deleted:
- error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
- elif user.external:
- error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
- elif not user.check_password( password ):
- error = "Invalid password"
- else:
- trans.handle_user_login( user )
- trans.log_event( "User logged in" )
- return error
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # error = password_error = None
+ # user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
+ # if not user:
+ # error = "No such user (please note that login is case sensitive)"
+ # elif user.deleted:
+ # error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
+ # elif user.external:
+ # error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
+ # elif not user.check_password( password ):
+ # error = "Invalid password"
+ # else:
+ # trans.handle_user_login( user )
+ # trans.log_event( "User logged in" )
+ # return error
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4835a8c8f01f/
Changeset: 4835a8c8f01f
Branch: stable
User: martenson
Date: 2014-12-04 17:00:38+00:00
Summary: Mobile version of galaxy at /mobile can't be navigated (many dead links etc.), the templates/controllers are completely unescaped so I am disabling it completely for now, until we fix or remove it.
Redirect to index from every used URL.
Affected #: 1 file
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r 4835a8c8f01f7a20a956bccec928c02f47cfe321 lib/galaxy/webapps/galaxy/controllers/mobile.py
--- a/lib/galaxy/webapps/galaxy/controllers/mobile.py
+++ b/lib/galaxy/webapps/galaxy/controllers/mobile.py
@@ -1,60 +1,71 @@
+from galaxy import web
from galaxy.web.base.controller import *
+
class Mobile( BaseUIController ):
+
@web.expose
def index( self, trans, **kwargs ):
- return trans.fill_template( "mobile/index.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/index.mako" )
@web.expose
def history_list( self, trans ):
- return trans.fill_template( "mobile/history/list.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/history/list.mako" )
@web.expose
def history_detail( self, trans, id ):
- history = trans.sa_session.query( trans.app.model.History ).get( id )
- assert history.user == trans.user
- return trans.fill_template( "mobile/history/detail.mako", history=history )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # history = trans.sa_session.query( trans.app.model.History ).get( id )
+ # assert history.user == trans.user
+ # return trans.fill_template( "mobile/history/detail.mako", history=history )
@web.expose
def dataset_detail( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
@web.expose
def dataset_peek( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
@web.expose
def settings( self, trans, email=None, password=None ):
- message = None
- if email is not None and password is not None:
- if email == "":
- self.__logout( trans )
- message = "Logged out"
- else:
- error = self.__login( trans, email, password )
- message = error or "Login changed"
- return trans.fill_template( "mobile/settings.mako", message=message )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # message = None
+ # if email is not None and password is not None:
+ # if email == "":
+ # self.__logout( trans )
+ # message = "Logged out"
+ # else:
+ # error = self.__login( trans, email, password )
+ # message = error or "Login changed"
+ # return trans.fill_template( "mobile/settings.mako", message=message )
def __logout( self, trans ):
- trans.log_event( "User logged out" )
- trans.handle_user_logout()
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # trans.log_event( "User logged out" )
+ # trans.handle_user_logout()
def __login( self, trans, email="", password="" ):
- error = password_error = None
- user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
- if not user:
- error = "No such user (please note that login is case sensitive)"
- elif user.deleted:
- error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
- elif user.external:
- error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
- elif not user.check_password( password ):
- error = "Invalid password"
- else:
- trans.handle_user_login( user )
- trans.log_event( "User logged in" )
- return error
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # error = password_error = None
+ # user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
+ # if not user:
+ # error = "No such user (please note that login is case sensitive)"
+ # elif user.deleted:
+ # error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
+ # elif user.external:
+ # error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
+ # elif not user.check_password( password ):
+ # error = "Invalid password"
+ # else:
+ # trans.handle_user_login( user )
+ # trans.log_event( "User logged in" )
+ # return error
https://bitbucket.org/galaxy/galaxy-central/commits/8e45b1cefba1/
Changeset: 8e45b1cefba1
Branch: stable
User: jmchilton
Date: 2014-12-05 16:57:27+00:00
Summary: Merged in martenson/galaxy-central-marten/stable (pull request #592)
[STABLE] disable mobile version of the website
Affected #: 1 file
diff -r f76fb3c40d55adf4f84acfdf26194d323f860df6 -r 8e45b1cefba16727d4d3a7d0dceaaaf1ef400a0c lib/galaxy/webapps/galaxy/controllers/mobile.py
--- a/lib/galaxy/webapps/galaxy/controllers/mobile.py
+++ b/lib/galaxy/webapps/galaxy/controllers/mobile.py
@@ -1,60 +1,71 @@
+from galaxy import web
from galaxy.web.base.controller import *
+
class Mobile( BaseUIController ):
+
@web.expose
def index( self, trans, **kwargs ):
- return trans.fill_template( "mobile/index.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/index.mako" )
@web.expose
def history_list( self, trans ):
- return trans.fill_template( "mobile/history/list.mako" )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # return trans.fill_template( "mobile/history/list.mako" )
@web.expose
def history_detail( self, trans, id ):
- history = trans.sa_session.query( trans.app.model.History ).get( id )
- assert history.user == trans.user
- return trans.fill_template( "mobile/history/detail.mako", history=history )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # history = trans.sa_session.query( trans.app.model.History ).get( id )
+ # assert history.user == trans.user
+ # return trans.fill_template( "mobile/history/detail.mako", history=history )
@web.expose
def dataset_detail( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/detail.mako", dataset=dataset )
@web.expose
def dataset_peek( self, trans, id ):
- dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
- assert dataset.history.user == trans.user
- return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # dataset = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( id )
+ # assert dataset.history.user == trans.user
+ # return trans.fill_template( "mobile/dataset/peek.mako", dataset=dataset )
@web.expose
def settings( self, trans, email=None, password=None ):
- message = None
- if email is not None and password is not None:
- if email == "":
- self.__logout( trans )
- message = "Logged out"
- else:
- error = self.__login( trans, email, password )
- message = error or "Login changed"
- return trans.fill_template( "mobile/settings.mako", message=message )
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # message = None
+ # if email is not None and password is not None:
+ # if email == "":
+ # self.__logout( trans )
+ # message = "Logged out"
+ # else:
+ # error = self.__login( trans, email, password )
+ # message = error or "Login changed"
+ # return trans.fill_template( "mobile/settings.mako", message=message )
def __logout( self, trans ):
- trans.log_event( "User logged out" )
- trans.handle_user_logout()
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # trans.log_event( "User logged out" )
+ # trans.handle_user_logout()
def __login( self, trans, email="", password="" ):
- error = password_error = None
- user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
- if not user:
- error = "No such user (please note that login is case sensitive)"
- elif user.deleted:
- error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
- elif user.external:
- error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
- elif not user.check_password( password ):
- error = "Invalid password"
- else:
- trans.handle_user_login( user )
- trans.log_event( "User logged in" )
- return error
+ return trans.response.send_redirect( web.url_for(controller='root', action='index' ) )
+ # error = password_error = None
+ # user = trans.sa_session.query( model.User ).filter_by( email = email ).first()
+ # if not user:
+ # error = "No such user (please note that login is case sensitive)"
+ # elif user.deleted:
+ # error = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
+ # elif user.external:
+ # error = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
+ # elif not user.check_password( password ):
+ # error = "Invalid password"
+ # else:
+ # trans.handle_user_login( user )
+ # trans.log_event( "User logged in" )
+ # return error
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: Merged in natefoo/galaxy-central/stable (pull request #588)
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f76fb3c40d55/
Changeset: f76fb3c40d55
Branch: stable
User: martenson
Date: 2014-12-05 16:54:22+00:00
Summary: Merged in natefoo/galaxy-central/stable (pull request #588)
[STABLE] XSS fixes for remaining user templates and a few other security fixes
Affected #: 6 files
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -1,6 +1,10 @@
+import logging
from galaxy.util import listify
from copy import deepcopy
+log = logging.getLogger( __name__ )
+
+
class FilterFactory( object ):
"""
An instance of this class is responsible for filtering the list
@@ -37,17 +41,21 @@
elif name == 'toolbox_label_filters':
category = "label"
if category:
- self.__init_filters( category, user_filters, filters )
+ validate = getattr( trans.app.config, 'user_%s_filters' % category, [] )
+ self.__init_filters( category, user_filters, filters, validate=validate )
else:
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
return filters
- def __init_filters( self, key, filters, toolbox_filters ):
+ def __init_filters( self, key, filters, toolbox_filters, validate=None ):
for filter in filters:
- filter_function = self.__build_filter_function( filter )
- toolbox_filters[ key ].append( filter_function )
+ if validate is None or filter in validate or filter in self.default_filters:
+ filter_function = self.__build_filter_function( filter )
+ toolbox_filters[ key ].append( filter_function )
+ else:
+ log.warning( "Refusing to load %s filter '%s' which is not defined in config", key, filter )
return toolbox_filters
def __build_filter_function( self, filter_name ):
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -295,7 +295,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -347,7 +347,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -453,7 +453,7 @@
redirect = self.__get_redirect_url( kwd.get( 'redirect', trans.request.referer ).strip() )
redirect_url = '' # always start with redirect_url being empty
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
- message = kwd.get( 'message', '' )
+ message = escape( kwd.get( 'message', '' ) )
status = kwd.get( 'status', 'done' )
header = ''
user = trans.user
@@ -606,7 +606,7 @@
refresh_frames = [ 'masthead' ]
trans.handle_user_logout( logout_all=logout_all )
message = 'You have been logged out.<br>You can log in again, <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
- ( trans.request.referer, url_for( '/' ) )
+ ( escape( trans.request.referer ), url_for( '/' ) )
if biostar.biostar_logged_in( trans ):
biostar_url = biostar.biostar_logout( trans )
if biostar_url:
@@ -629,7 +629,7 @@
if honeypot_field != '':
return trans.show_error_message( "You've been flagged as a possible bot. If you are not, please try registering again and fill the form out carefully. <a target=\"_top\" href=\"%s\">Go to the home page</a>." ) % url_for( '/' )
- message = util.restore_text( params.get( 'message', '' ) )
+ message = escape( util.restore_text( params.get( 'message', '' ) ) )
status = params.get( 'status', 'done' )
use_panels = util.string_as_bool( kwd.get( 'use_panels', True ) )
email = util.restore_text( params.get( 'email', '' ) )
@@ -659,9 +659,11 @@
# Create the user, save all the user info and login to Galaxy
if params.get( 'create_user_button', False ):
# Check email and password validity
+ # Note: message does not need to be escaped (it is clean)
message = self.__validate( trans, params, email, password, confirm, username )
if not message:
# All the values are valid
+ # message does not need to be escaped here either
message, status, user, success = self.__register( trans,
cntrller,
subscribe_checked,
@@ -675,7 +677,7 @@
trans.log_event( "User created a new account" )
trans.log_event( "User logged in" )
if success and is_admin:
- message = 'Created new user account (%s)' % user.email
+ message = 'Created new user account (%s)' % escape( user.email )
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
cntrller=cntrller,
@@ -743,7 +745,7 @@
if subscribe_checked:
# subscribe user to email list
if trans.app.config.smtp_server is None:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
else:
body = 'Join Mailing list.\n'
to = trans.app.config.mailing_join_addr
@@ -752,7 +754,7 @@
try:
util.send_mail( frm, to, subject, body, trans.app.config )
except:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed."
if not error and not is_admin:
# The handle_user_login() method has a call to the history_set_default_permissions() method
# (needed when logging in with a history), user needs to have default permissions set before logging in
@@ -762,7 +764,7 @@
elif not error:
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
- message='Created new user account (%s)' % user.email,
+ message='Created new user account (%s)' % escape( user.email ),
status=status ) )
if error:
message = error
@@ -772,7 +774,7 @@
if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on:
is_activation_sent = self.send_verification_email( trans, email, username )
if is_activation_sent:
- message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
else:
message = 'Unable to send activation email, please contact your local Galaxy administrator.'
@@ -780,7 +782,7 @@
message += ' Contact: %s' % trans.app.config.error_email_to
success = False
else: # User activation is OFF, proceed without sending the activation email.
- message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
return ( message, status, user, success )
@@ -970,7 +972,7 @@
user.username = username
trans.sa_session.add( user )
trans.sa_session.flush()
- message = 'The username has been updated with the changes.'
+ message = 'The username has been updated to: %s' % escape( username )
return trans.fill_template( '/user/username.mako',
cntrller=cntrller,
user=user,
@@ -1177,7 +1179,7 @@
message = 'Default new history permissions have been changed.'
return trans.fill_template( 'user/permissions.mako',
cntrller=cntrller,
- message=message,
+ message=escape( message ),
status=status )
else:
# User not logged in, history group must be only public
@@ -1228,57 +1230,48 @@
filters.append( dict( filterpath=filter_name, short_desc=sdesc, desc=description, checked=False ) )
return filters
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ saved_user_tool_filters = list()
+ saved_user_section_filters = list()
+ saved_user_label_filters = list()
- user_id = params.get( 'user_id', False )
- if user_id:
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
- else:
- user = trans.user
+ for name, value in trans.user.preferences.items():
+ if name == 'toolbox_tool_filters':
+ saved_user_tool_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_section_filters':
+ saved_user_section_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_label_filters':
+ saved_user_label_filters = listify( value, do_strip=True )
- if user:
- saved_user_tool_filters = list()
- saved_user_section_filters = list()
- saved_user_label_filters = list()
+ tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
+ section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
+ label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
- for name, value in user.preferences.items():
- if name == 'toolbox_tool_filters':
- saved_user_tool_filters = listify( value, do_strip=True )
- elif name == 'toolbox_section_filters':
- saved_user_section_filters = listify( value, do_strip=True )
- elif name == 'toolbox_label_filters':
- saved_user_label_filters = listify( value, do_strip=True )
+ message = escape( util.restore_text( kwd.get( 'message', '' ) ) )
+ status = util.restore_text( kwd.get( 'status', 'done' ) )
- tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
- section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
- label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
-
- return trans.fill_template( 'user/toolbox_filters.mako',
- cntrller=cntrller,
- message=message,
- tool_filters=tool_filters,
- section_filters=section_filters,
- label_filters=label_filters,
- user=user,
- status=status )
- else:
- # User not logged in, history group must be only public
- return trans.show_error_message( "You must be logged in to change private toolbox filters." )
+ return trans.fill_template( 'user/toolbox_filters.mako',
+ cntrller=cntrller,
+ message=message,
+ tool_filters=tool_filters,
+ section_filters=section_filters,
+ label_filters=label_filters,
+ user=trans.user,
+ status=status)
@web.expose
@web.require_login( "to change the private toolbox filters" )
def edit_toolbox_filters( self, trans, cntrller, **kwd ):
+ def validate( user_filters, filter_type ):
+ rval = []
+ config_filters = getattr( trans.app.config, 'user_%s_filters' % filter_type, [] )
+ for f in user_filters:
+ if f not in config_filters:
+ log.warning( 'User provided filter %s which is not in user_%s_filters', f, filter_type )
+ else:
+ rval.append( f )
+ return rval
+
params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- user_id = params.get( 'user_id', False )
- if not user_id:
- # User must be logged in to create a new address
- return trans.show_error_message( "You must be logged in to change the ToolBox filters." )
-
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
-
if params.get( 'edit_toolbox_filter_button', False ):
tool_filters = list()
section_filters = list()
@@ -1291,13 +1284,13 @@
label_filters.append( name[2:] )
elif name.startswith('s_'):
section_filters.append( name[2:] )
- user.preferences['toolbox_tool_filters'] = ','.join( tool_filters )
- user.preferences['toolbox_section_filters'] = ','.join( section_filters )
- user.preferences['toolbox_label_filters'] = ','.join( label_filters )
+ trans.user.preferences['toolbox_tool_filters'] = ','.join( validate( tool_filters, 'tool' ) )
+ trans.user.preferences['toolbox_section_filters'] = ','.join( validate( section_filters, 'section' ) )
+ trans.user.preferences['toolbox_label_filters'] = ','.join( validate( label_filters, 'label' ) )
- trans.sa_session.add( user )
+ trans.sa_session.add( trans.user )
trans.sa_session.flush()
- message = 'ToolBox filters has been updated.'
+ message = 'ToolBox filters have been updated.'
kwd = dict( message=message, status='done' )
# Display the ToolBox filters form with the current values filled in
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/dbkeys.mako
--- a/templates/user/dbkeys.mako
+++ b/templates/user/dbkeys.mako
@@ -148,7 +148,7 @@
Processing
% endif
</td>
- <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key}" /><input type="submit" name="delete" value="Delete" /></form></td>
+ <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key | h}" /><input type="submit" name="delete" value="Delete" /></form></td></tr>
% endfor
</table>
@@ -194,7 +194,7 @@
<div style="clear: both; padding-bottom: 0.5em"></div><select id="fasta_input" name="dataset_id">
%for dataset in fasta_hdas:
- <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid}: ${dataset.name}</option>
+ <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid | h}: ${dataset.name | h}</option>
%endfor
</select><input type="file" id="len_file_input" name="len_file" /></input>
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/openid_associate.mako
--- a/templates/user/openid_associate.mako
+++ b/templates/user/openid_associate.mako
@@ -48,13 +48,13 @@
The following OpenIDs will be associated with the account chosen or created below.
<ul>
%for openid in openids:
- <li>${openid.openid}</li>
+ <li>${openid.openid | h}</li>
%endfor
</ul></div>
%else:
<div>
- The OpenID <strong>${openids[0].openid}</strong> will be associated with the account chosen or created.
+ The OpenID <strong>${openids[0].openid | h}</strong> will be associated with the account chosen or created.
</div>
%endif
<br/>
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/toolbox_filters.mako
--- a/templates/user/toolbox_filters.mako
+++ b/templates/user/toolbox_filters.mako
@@ -15,7 +15,7 @@
%if tool_filters or section_filters or label_filters:
<div class="toolForm">
- <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller, user_id=trans.security.encode_id( user.id ) )}" method="post" >
+ <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller )}" method="post" >
% if tool_filters:
<div class="toolFormTitle">Edit ToolBox filters :: Tools</div><div class="toolFormBody">
@@ -87,5 +87,5 @@
</form></div>
%else:
- ${render_msg( 'No filter available. Contact you system administrator or check your configuration file.', 'info' )}
+ ${render_msg( 'No filters available. Contact your system administrator or check your configuration file.', 'info' )}
%endif
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/username.mako
--- a/templates/user/username.mako
+++ b/templates/user/username.mako
@@ -1,4 +1,9 @@
<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
<% is_admin = cntrller == 'admin' and trans.user_is_admin() %>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/98ed01f41e80/
Changeset: 98ed01f41e80
Branch: stable
User: natefoo
Date: 2014-12-03 17:23:01+00:00
Summary: Validate that toolbox filters specified by the user have been configured by the administrator.
Affected #: 3 files
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -1,6 +1,10 @@
+import logging
from galaxy.util import listify
from copy import deepcopy
+log = logging.getLogger( __name__ )
+
+
class FilterFactory( object ):
"""
An instance of this class is responsible for filtering the list
@@ -37,17 +41,21 @@
elif name == 'toolbox_label_filters':
category = "label"
if category:
- self.__init_filters( category, user_filters, filters )
+ validate = getattr( trans.app.config, 'user_%s_filters' % category, [] )
+ self.__init_filters( category, user_filters, filters, validate=validate )
else:
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
return filters
- def __init_filters( self, key, filters, toolbox_filters ):
+ def __init_filters( self, key, filters, toolbox_filters, validate=None ):
for filter in filters:
- filter_function = self.__build_filter_function( filter )
- toolbox_filters[ key ].append( filter_function )
+ if validate is None or filter in validate or filter in self.default_filters:
+ filter_function = self.__build_filter_function( filter )
+ toolbox_filters[ key ].append( filter_function )
+ else:
+ log.warning( "Refusing to load %s filter '%s' which is not defined in config", key, filter )
return toolbox_filters
def __build_filter_function( self, filter_name ):
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -1228,57 +1228,48 @@
filters.append( dict( filterpath=filter_name, short_desc=sdesc, desc=description, checked=False ) )
return filters
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ saved_user_tool_filters = list()
+ saved_user_section_filters = list()
+ saved_user_label_filters = list()
- user_id = params.get( 'user_id', False )
- if user_id:
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
- else:
- user = trans.user
+ for name, value in trans.user.preferences.items():
+ if name == 'toolbox_tool_filters':
+ saved_user_tool_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_section_filters':
+ saved_user_section_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_label_filters':
+ saved_user_label_filters = listify( value, do_strip=True )
- if user:
- saved_user_tool_filters = list()
- saved_user_section_filters = list()
- saved_user_label_filters = list()
+ tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
+ section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
+ label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
- for name, value in user.preferences.items():
- if name == 'toolbox_tool_filters':
- saved_user_tool_filters = listify( value, do_strip=True )
- elif name == 'toolbox_section_filters':
- saved_user_section_filters = listify( value, do_strip=True )
- elif name == 'toolbox_label_filters':
- saved_user_label_filters = listify( value, do_strip=True )
+ message = escape( util.restore_text( kwd.get( 'message', '' ) ) )
+ status = util.restore_text( kwd.get( 'status', 'done' ) )
- tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
- section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
- label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
-
- return trans.fill_template( 'user/toolbox_filters.mako',
- cntrller=cntrller,
- message=message,
- tool_filters=tool_filters,
- section_filters=section_filters,
- label_filters=label_filters,
- user=user,
- status=status )
- else:
- # User not logged in, history group must be only public
- return trans.show_error_message( "You must be logged in to change private toolbox filters." )
+ return trans.fill_template( 'user/toolbox_filters.mako',
+ cntrller=cntrller,
+ message=message,
+ tool_filters=tool_filters,
+ section_filters=section_filters,
+ label_filters=label_filters,
+ user=trans.user,
+ status=status)
@web.expose
@web.require_login( "to change the private toolbox filters" )
def edit_toolbox_filters( self, trans, cntrller, **kwd ):
+ def validate( user_filters, filter_type ):
+ rval = []
+ config_filters = getattr( trans.app.config, 'user_%s_filters' % filter_type, [] )
+ for f in user_filters:
+ if f not in config_filters:
+ log.warning( 'User provided filter %s which is not in user_%s_filters', f, filter_type )
+ else:
+ rval.append( f )
+ return rval
+
params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- user_id = params.get( 'user_id', False )
- if not user_id:
- # User must be logged in to create a new address
- return trans.show_error_message( "You must be logged in to change the ToolBox filters." )
-
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
-
if params.get( 'edit_toolbox_filter_button', False ):
tool_filters = list()
section_filters = list()
@@ -1291,13 +1282,13 @@
label_filters.append( name[2:] )
elif name.startswith('s_'):
section_filters.append( name[2:] )
- user.preferences['toolbox_tool_filters'] = ','.join( tool_filters )
- user.preferences['toolbox_section_filters'] = ','.join( section_filters )
- user.preferences['toolbox_label_filters'] = ','.join( label_filters )
+ trans.user.preferences['toolbox_tool_filters'] = ','.join( validate( tool_filters, 'tool' ) )
+ trans.user.preferences['toolbox_section_filters'] = ','.join( validate( section_filters, 'section' ) )
+ trans.user.preferences['toolbox_label_filters'] = ','.join( validate( label_filters, 'label' ) )
- trans.sa_session.add( user )
+ trans.sa_session.add( trans.user )
trans.sa_session.flush()
- message = 'ToolBox filters has been updated.'
+ message = 'ToolBox filters have been updated.'
kwd = dict( message=message, status='done' )
# Display the ToolBox filters form with the current values filled in
diff -r 546ff6ef27b4b83e26ae228c292fd981173ac550 -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 templates/user/toolbox_filters.mako
--- a/templates/user/toolbox_filters.mako
+++ b/templates/user/toolbox_filters.mako
@@ -15,7 +15,7 @@
%if tool_filters or section_filters or label_filters:
<div class="toolForm">
- <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller, user_id=trans.security.encode_id( user.id ) )}" method="post" >
+ <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller )}" method="post" >
% if tool_filters:
<div class="toolFormTitle">Edit ToolBox filters :: Tools</div><div class="toolFormBody">
@@ -87,5 +87,5 @@
</form></div>
%else:
- ${render_msg( 'No filter available. Contact you system administrator or check your configuration file.', 'info' )}
+ ${render_msg( 'No filters available. Contact your system administrator or check your configuration file.', 'info' )}
%endif
https://bitbucket.org/galaxy/galaxy-central/commits/c0e27e99def9/
Changeset: c0e27e99def9
Branch: stable
User: natefoo
Date: 2014-12-03 20:57:58+00:00
Summary: Remaining user function template XSS cleanup. Also fix login redirection security in the OpenID methods.
Affected #: 4 files
diff -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 -r c0e27e99def95496603c9c63aee17ac48203de50 lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -295,7 +295,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -347,7 +347,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -453,7 +453,7 @@
redirect = self.__get_redirect_url( kwd.get( 'redirect', trans.request.referer ).strip() )
redirect_url = '' # always start with redirect_url being empty
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
- message = kwd.get( 'message', '' )
+ message = escape( kwd.get( 'message', '' ) )
status = kwd.get( 'status', 'done' )
header = ''
user = trans.user
@@ -606,7 +606,7 @@
refresh_frames = [ 'masthead' ]
trans.handle_user_logout( logout_all=logout_all )
message = 'You have been logged out.<br>You can log in again, <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
- ( trans.request.referer, url_for( '/' ) )
+ ( escape( trans.request.referer ), url_for( '/' ) )
if biostar.biostar_logged_in( trans ):
biostar_url = biostar.biostar_logout( trans )
if biostar_url:
@@ -629,7 +629,7 @@
if honeypot_field != '':
return trans.show_error_message( "You've been flagged as a possible bot. If you are not, please try registering again and fill the form out carefully. <a target=\"_top\" href=\"%s\">Go to the home page</a>." ) % url_for( '/' )
- message = util.restore_text( params.get( 'message', '' ) )
+ message = escape( util.restore_text( params.get( 'message', '' ) ) )
status = params.get( 'status', 'done' )
use_panels = util.string_as_bool( kwd.get( 'use_panels', True ) )
email = util.restore_text( params.get( 'email', '' ) )
@@ -659,9 +659,11 @@
# Create the user, save all the user info and login to Galaxy
if params.get( 'create_user_button', False ):
# Check email and password validity
+ # Note: message does not need to be escaped (it is clean)
message = self.__validate( trans, params, email, password, confirm, username )
if not message:
# All the values are valid
+ # message does not need to be escaped here either
message, status, user, success = self.__register( trans,
cntrller,
subscribe_checked,
@@ -675,7 +677,7 @@
trans.log_event( "User created a new account" )
trans.log_event( "User logged in" )
if success and is_admin:
- message = 'Created new user account (%s)' % user.email
+ message = 'Created new user account (%s)' % escape( user.email )
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
cntrller=cntrller,
@@ -743,7 +745,7 @@
if subscribe_checked:
# subscribe user to email list
if trans.app.config.smtp_server is None:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
else:
body = 'Join Mailing list.\n'
to = trans.app.config.mailing_join_addr
@@ -752,7 +754,7 @@
try:
util.send_mail( frm, to, subject, body, trans.app.config )
except:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed."
if not error and not is_admin:
# The handle_user_login() method has a call to the history_set_default_permissions() method
# (needed when logging in with a history), user needs to have default permissions set before logging in
@@ -762,7 +764,7 @@
elif not error:
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
- message='Created new user account (%s)' % user.email,
+ message='Created new user account (%s)' % escape( user.email ),
status=status ) )
if error:
message = error
@@ -772,7 +774,7 @@
if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on:
is_activation_sent = self.send_verification_email( trans, email, username )
if is_activation_sent:
- message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
else:
message = 'Unable to send activation email, please contact your local Galaxy administrator.'
@@ -780,7 +782,7 @@
message += ' Contact: %s' % trans.app.config.error_email_to
success = False
else: # User activation is OFF, proceed without sending the activation email.
- message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
return ( message, status, user, success )
@@ -970,7 +972,7 @@
user.username = username
trans.sa_session.add( user )
trans.sa_session.flush()
- message = 'The username has been updated with the changes.'
+ message = 'The username has been updated to: %s' % escape( username )
return trans.fill_template( '/user/username.mako',
cntrller=cntrller,
user=user,
@@ -1177,7 +1179,7 @@
message = 'Default new history permissions have been changed.'
return trans.fill_template( 'user/permissions.mako',
cntrller=cntrller,
- message=message,
+ message=escape( message ),
status=status )
else:
# User not logged in, history group must be only public
diff -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 -r c0e27e99def95496603c9c63aee17ac48203de50 templates/user/dbkeys.mako
--- a/templates/user/dbkeys.mako
+++ b/templates/user/dbkeys.mako
@@ -148,7 +148,7 @@
Processing
% endif
</td>
- <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key}" /><input type="submit" name="delete" value="Delete" /></form></td>
+ <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key | h}" /><input type="submit" name="delete" value="Delete" /></form></td></tr>
% endfor
</table>
@@ -194,7 +194,7 @@
<div style="clear: both; padding-bottom: 0.5em"></div><select id="fasta_input" name="dataset_id">
%for dataset in fasta_hdas:
- <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid}: ${dataset.name}</option>
+ <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid | h}: ${dataset.name | h}</option>
%endfor
</select><input type="file" id="len_file_input" name="len_file" /></input>
diff -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 -r c0e27e99def95496603c9c63aee17ac48203de50 templates/user/openid_associate.mako
--- a/templates/user/openid_associate.mako
+++ b/templates/user/openid_associate.mako
@@ -48,13 +48,13 @@
The following OpenIDs will be associated with the account chosen or created below.
<ul>
%for openid in openids:
- <li>${openid.openid}</li>
+ <li>${openid.openid | h}</li>
%endfor
</ul></div>
%else:
<div>
- The OpenID <strong>${openids[0].openid}</strong> will be associated with the account chosen or created.
+ The OpenID <strong>${openids[0].openid | h}</strong> will be associated with the account chosen or created.
</div>
%endif
<br/>
diff -r 98ed01f41e8005d7165a78db25ccab3e0bbe2291 -r c0e27e99def95496603c9c63aee17ac48203de50 templates/user/username.mako
--- a/templates/user/username.mako
+++ b/templates/user/username.mako
@@ -1,4 +1,9 @@
<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
<% is_admin = cntrller == 'admin' and trans.user_is_admin() %>
https://bitbucket.org/galaxy/galaxy-central/commits/f76fb3c40d55/
Changeset: f76fb3c40d55
Branch: stable
User: martenson
Date: 2014-12-05 16:54:22+00:00
Summary: Merged in natefoo/galaxy-central/stable (pull request #588)
[STABLE] XSS fixes for remaining user templates and a few other security fixes
Affected #: 6 files
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 lib/galaxy/tools/filters/__init__.py
--- a/lib/galaxy/tools/filters/__init__.py
+++ b/lib/galaxy/tools/filters/__init__.py
@@ -1,6 +1,10 @@
+import logging
from galaxy.util import listify
from copy import deepcopy
+log = logging.getLogger( __name__ )
+
+
class FilterFactory( object ):
"""
An instance of this class is responsible for filtering the list
@@ -37,17 +41,21 @@
elif name == 'toolbox_label_filters':
category = "label"
if category:
- self.__init_filters( category, user_filters, filters )
+ validate = getattr( trans.app.config, 'user_%s_filters' % category, [] )
+ self.__init_filters( category, user_filters, filters, validate=validate )
else:
if kwds.get( "trackster", False ):
filters[ "tool" ].append( _has_trackster_conf )
return filters
- def __init_filters( self, key, filters, toolbox_filters ):
+ def __init_filters( self, key, filters, toolbox_filters, validate=None ):
for filter in filters:
- filter_function = self.__build_filter_function( filter )
- toolbox_filters[ key ].append( filter_function )
+ if validate is None or filter in validate or filter in self.default_filters:
+ filter_function = self.__build_filter_function( filter )
+ toolbox_filters[ key ].append( filter_function )
+ else:
+ log.warning( "Refusing to load %s filter '%s' which is not defined in config", key, filter )
return toolbox_filters
def __build_filter_function( self, filter_name ):
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 lib/galaxy/webapps/galaxy/controllers/user.py
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -295,7 +295,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -347,7 +347,7 @@
message=message,
status='info' ) )
if redirect:
- return trans.response.send_redirect( redirect )
+ return trans.response.send_redirect( self.__get_redirect_url( redirect ) )
return trans.response.send_redirect( url_for( controller='user',
action='openid_manage',
use_panels=use_panels,
@@ -453,7 +453,7 @@
redirect = self.__get_redirect_url( kwd.get( 'redirect', trans.request.referer ).strip() )
redirect_url = '' # always start with redirect_url being empty
use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
- message = kwd.get( 'message', '' )
+ message = escape( kwd.get( 'message', '' ) )
status = kwd.get( 'status', 'done' )
header = ''
user = trans.user
@@ -606,7 +606,7 @@
refresh_frames = [ 'masthead' ]
trans.handle_user_logout( logout_all=logout_all )
message = 'You have been logged out.<br>You can log in again, <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
- ( trans.request.referer, url_for( '/' ) )
+ ( escape( trans.request.referer ), url_for( '/' ) )
if biostar.biostar_logged_in( trans ):
biostar_url = biostar.biostar_logout( trans )
if biostar_url:
@@ -629,7 +629,7 @@
if honeypot_field != '':
return trans.show_error_message( "You've been flagged as a possible bot. If you are not, please try registering again and fill the form out carefully. <a target=\"_top\" href=\"%s\">Go to the home page</a>." ) % url_for( '/' )
- message = util.restore_text( params.get( 'message', '' ) )
+ message = escape( util.restore_text( params.get( 'message', '' ) ) )
status = params.get( 'status', 'done' )
use_panels = util.string_as_bool( kwd.get( 'use_panels', True ) )
email = util.restore_text( params.get( 'email', '' ) )
@@ -659,9 +659,11 @@
# Create the user, save all the user info and login to Galaxy
if params.get( 'create_user_button', False ):
# Check email and password validity
+ # Note: message does not need to be escaped (it is clean)
message = self.__validate( trans, params, email, password, confirm, username )
if not message:
# All the values are valid
+ # message does not need to be escaped here either
message, status, user, success = self.__register( trans,
cntrller,
subscribe_checked,
@@ -675,7 +677,7 @@
trans.log_event( "User created a new account" )
trans.log_event( "User logged in" )
if success and is_admin:
- message = 'Created new user account (%s)' % user.email
+ message = 'Created new user account (%s)' % escape( user.email )
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
cntrller=cntrller,
@@ -743,7 +745,7 @@
if subscribe_checked:
# subscribe user to email list
if trans.app.config.smtp_server is None:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
else:
body = 'Join Mailing list.\n'
to = trans.app.config.mailing_join_addr
@@ -752,7 +754,7 @@
try:
util.send_mail( frm, to, subject, body, trans.app.config )
except:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
+ error = "Now logged in as " + escape( user.email ) + ". However, subscribing to the mailing list has failed."
if not error and not is_admin:
# The handle_user_login() method has a call to the history_set_default_permissions() method
# (needed when logging in with a history), user needs to have default permissions set before logging in
@@ -762,7 +764,7 @@
elif not error:
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
- message='Created new user account (%s)' % user.email,
+ message='Created new user account (%s)' % escape( user.email ),
status=status ) )
if error:
message = error
@@ -772,7 +774,7 @@
if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on:
is_activation_sent = self.send_verification_email( trans, email, username )
if is_activation_sent:
- message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
else:
message = 'Unable to send activation email, please contact your local Galaxy administrator.'
@@ -780,7 +782,7 @@
message += ' Contact: %s' % trans.app.config.error_email_to
success = False
else: # User activation is OFF, proceed without sending the activation email.
- message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( escape( user.email ), url_for( '/' ) )
success = True
return ( message, status, user, success )
@@ -970,7 +972,7 @@
user.username = username
trans.sa_session.add( user )
trans.sa_session.flush()
- message = 'The username has been updated with the changes.'
+ message = 'The username has been updated to: %s' % escape( username )
return trans.fill_template( '/user/username.mako',
cntrller=cntrller,
user=user,
@@ -1177,7 +1179,7 @@
message = 'Default new history permissions have been changed.'
return trans.fill_template( 'user/permissions.mako',
cntrller=cntrller,
- message=message,
+ message=escape( message ),
status=status )
else:
# User not logged in, history group must be only public
@@ -1228,57 +1230,48 @@
filters.append( dict( filterpath=filter_name, short_desc=sdesc, desc=description, checked=False ) )
return filters
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
+ saved_user_tool_filters = list()
+ saved_user_section_filters = list()
+ saved_user_label_filters = list()
- user_id = params.get( 'user_id', False )
- if user_id:
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
- else:
- user = trans.user
+ for name, value in trans.user.preferences.items():
+ if name == 'toolbox_tool_filters':
+ saved_user_tool_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_section_filters':
+ saved_user_section_filters = listify( value, do_strip=True )
+ elif name == 'toolbox_label_filters':
+ saved_user_label_filters = listify( value, do_strip=True )
- if user:
- saved_user_tool_filters = list()
- saved_user_section_filters = list()
- saved_user_label_filters = list()
+ tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
+ section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
+ label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
- for name, value in user.preferences.items():
- if name == 'toolbox_tool_filters':
- saved_user_tool_filters = listify( value, do_strip=True )
- elif name == 'toolbox_section_filters':
- saved_user_section_filters = listify( value, do_strip=True )
- elif name == 'toolbox_label_filters':
- saved_user_label_filters = listify( value, do_strip=True )
+ message = escape( util.restore_text( kwd.get( 'message', '' ) ) )
+ status = util.restore_text( kwd.get( 'status', 'done' ) )
- tool_filters = get_filter_mapping( saved_user_tool_filters, trans.app.config.user_tool_filters )
- section_filters = get_filter_mapping( saved_user_section_filters, trans.app.config.user_section_filters )
- label_filters = get_filter_mapping( saved_user_label_filters, trans.app.config.user_label_filters )
-
- return trans.fill_template( 'user/toolbox_filters.mako',
- cntrller=cntrller,
- message=message,
- tool_filters=tool_filters,
- section_filters=section_filters,
- label_filters=label_filters,
- user=user,
- status=status )
- else:
- # User not logged in, history group must be only public
- return trans.show_error_message( "You must be logged in to change private toolbox filters." )
+ return trans.fill_template( 'user/toolbox_filters.mako',
+ cntrller=cntrller,
+ message=message,
+ tool_filters=tool_filters,
+ section_filters=section_filters,
+ label_filters=label_filters,
+ user=trans.user,
+ status=status)
@web.expose
@web.require_login( "to change the private toolbox filters" )
def edit_toolbox_filters( self, trans, cntrller, **kwd ):
+ def validate( user_filters, filter_type ):
+ rval = []
+ config_filters = getattr( trans.app.config, 'user_%s_filters' % filter_type, [] )
+ for f in user_filters:
+ if f not in config_filters:
+ log.warning( 'User provided filter %s which is not in user_%s_filters', f, filter_type )
+ else:
+ rval.append( f )
+ return rval
+
params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- user_id = params.get( 'user_id', False )
- if not user_id:
- # User must be logged in to create a new address
- return trans.show_error_message( "You must be logged in to change the ToolBox filters." )
-
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) )
-
if params.get( 'edit_toolbox_filter_button', False ):
tool_filters = list()
section_filters = list()
@@ -1291,13 +1284,13 @@
label_filters.append( name[2:] )
elif name.startswith('s_'):
section_filters.append( name[2:] )
- user.preferences['toolbox_tool_filters'] = ','.join( tool_filters )
- user.preferences['toolbox_section_filters'] = ','.join( section_filters )
- user.preferences['toolbox_label_filters'] = ','.join( label_filters )
+ trans.user.preferences['toolbox_tool_filters'] = ','.join( validate( tool_filters, 'tool' ) )
+ trans.user.preferences['toolbox_section_filters'] = ','.join( validate( section_filters, 'section' ) )
+ trans.user.preferences['toolbox_label_filters'] = ','.join( validate( label_filters, 'label' ) )
- trans.sa_session.add( user )
+ trans.sa_session.add( trans.user )
trans.sa_session.flush()
- message = 'ToolBox filters has been updated.'
+ message = 'ToolBox filters have been updated.'
kwd = dict( message=message, status='done' )
# Display the ToolBox filters form with the current values filled in
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/dbkeys.mako
--- a/templates/user/dbkeys.mako
+++ b/templates/user/dbkeys.mako
@@ -148,7 +148,7 @@
Processing
% endif
</td>
- <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key}" /><input type="submit" name="delete" value="Delete" /></form></td>
+ <td><form action="dbkeys" method="post"><input type="hidden" name="key" value="${key | h}" /><input type="submit" name="delete" value="Delete" /></form></td></tr>
% endfor
</table>
@@ -194,7 +194,7 @@
<div style="clear: both; padding-bottom: 0.5em"></div><select id="fasta_input" name="dataset_id">
%for dataset in fasta_hdas:
- <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid}: ${dataset.name}</option>
+ <option value="${trans.security.encode_id( dataset.id )}">${dataset.hid | h}: ${dataset.name | h}</option>
%endfor
</select><input type="file" id="len_file_input" name="len_file" /></input>
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/openid_associate.mako
--- a/templates/user/openid_associate.mako
+++ b/templates/user/openid_associate.mako
@@ -48,13 +48,13 @@
The following OpenIDs will be associated with the account chosen or created below.
<ul>
%for openid in openids:
- <li>${openid.openid}</li>
+ <li>${openid.openid | h}</li>
%endfor
</ul></div>
%else:
<div>
- The OpenID <strong>${openids[0].openid}</strong> will be associated with the account chosen or created.
+ The OpenID <strong>${openids[0].openid | h}</strong> will be associated with the account chosen or created.
</div>
%endif
<br/>
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/toolbox_filters.mako
--- a/templates/user/toolbox_filters.mako
+++ b/templates/user/toolbox_filters.mako
@@ -15,7 +15,7 @@
%if tool_filters or section_filters or label_filters:
<div class="toolForm">
- <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller, user_id=trans.security.encode_id( user.id ) )}" method="post" >
+ <form name="toolbox_filter" id="toolbox_filter" action="${h.url_for( controller='user', action='edit_toolbox_filters', cntrller=cntrller )}" method="post" >
% if tool_filters:
<div class="toolFormTitle">Edit ToolBox filters :: Tools</div><div class="toolFormBody">
@@ -87,5 +87,5 @@
</form></div>
%else:
- ${render_msg( 'No filter available. Contact you system administrator or check your configuration file.', 'info' )}
+ ${render_msg( 'No filters available. Contact your system administrator or check your configuration file.', 'info' )}
%endif
diff -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 -r f76fb3c40d55adf4f84acfdf26194d323f860df6 templates/user/username.mako
--- a/templates/user/username.mako
+++ b/templates/user/username.mako
@@ -1,4 +1,9 @@
<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
<% is_admin = cntrller == 'admin' and trans.user_is_admin() %>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: Merged in dan/galaxy-central-prs/stable (pull request #593)
by commits-noreply@bitbucket.org 05 Dec '14
by commits-noreply@bitbucket.org 05 Dec '14
05 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/de92a7b85033/
Changeset: de92a7b85033
Branch: stable
User: martenson
Date: 2014-12-05 16:49:14+00:00
Summary: Merged in dan/galaxy-central-prs/stable (pull request #593)
[STABLE] Some web sanitization for Data Managers and Biostar redirect.
Affected #: 4 files
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 lib/galaxy/webapps/galaxy/controllers/data_manager.py
--- a/lib/galaxy/webapps/galaxy/controllers/data_manager.py
+++ b/lib/galaxy/webapps/galaxy/controllers/data_manager.py
@@ -7,6 +7,8 @@
pkg_resources.require( "Paste" )
import paste.httpexceptions
+from galaxy.web.framework.helpers import escape
+
#set up logger
import logging
log = logging.getLogger( __name__ )
@@ -18,8 +20,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
return trans.fill_template( "data_manager/index.mako", data_managers=trans.app.data_managers, tool_data_tables=trans.app.tool_data_tables, view_only=not_is_admin, message=message, status=status )
@web.expose
@@ -27,8 +29,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_manager_id = kwd.get( 'id', None )
data_manager = trans.app.data_managers.get_manager( data_manager_id )
if data_manager is None:
@@ -41,8 +43,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
job_id = kwd.get( 'id', None )
try:
job_id = trans.security.decode_id( job_id )
@@ -62,7 +64,7 @@
data_manager_json = loads( open( hda.get_file_name() ).read() )
except Exception, e:
data_manager_json = {}
- error_messages.append( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) )
+ error_messages.append( escape( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) ) )
values = []
for key, value in data_manager_json.get( 'data_tables', {} ).iteritems():
values.append( ( key, value ) )
@@ -74,8 +76,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_table_name = kwd.get( 'table_name', None )
if not data_table_name:
return trans.response.send_redirect( web.url_for( controller="data_manager", action="index" ) )
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/biostar/post_redirect.mako
--- a/templates/webapps/galaxy/biostar/post_redirect.mako
+++ b/templates/webapps/galaxy/biostar/post_redirect.mako
@@ -18,7 +18,7 @@
<p>If you are not automatically forwarded, click the button below:<p><form id="postRedirectForm" action="${post_url}" method="post" >
%for input_name, input_value in form_inputs.items():
- <input type="hidden" name="${input_name}" value="${input_value | h}">
+ <input type="hidden" name="${input_name | h}" value="${input_value | h}">
%endfor
<input type="submit" name="GalaxySubmitPostRedirectForm" id='GalaxySubmitPostRedirectForm' value="Click Here"></form>
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/data_manager/manage_data_table.mako
--- a/templates/webapps/galaxy/data_manager/manage_data_table.mako
+++ b/templates/webapps/galaxy/data_manager/manage_data_table.mako
@@ -14,9 +14,9 @@
<% column_name_list = data_table.get_column_name_list() %><table class="tabletip"><thead>
- <tr><th colspan="${len (column_name_list) }" style="font-size: 120%;">
+ <tr><th colspan="${ len( column_name_list ) | h}" style="font-size: 120%;">
Data Manager: ${ data_table.name | h }
- <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name} tool data table" data-placement="bottom">
+ <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name | h} tool data table" data-placement="bottom"><span class="fa fa-refresh"></span></a></th></tr>
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/data_manager/view_job.mako
--- a/templates/webapps/galaxy/data_manager/view_job.mako
+++ b/templates/webapps/galaxy/data_manager/view_job.mako
@@ -26,8 +26,8 @@
</thead><tbody><tr><td>Name:</td><td>${hda.name | h}</td></tr>
- <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format)}</td></tr>
- <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size)}</td></tr>
+ <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format) | h}</td></tr>
+ <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size) | h}</td></tr><tr><td>Tool Exit Code:</td><td>${job.exit_code | h}</td></tr><tr><td>Full Path:</td><td>${hda.file_name | h}</td></tr><tr><td>View complete info:</td><td><a href="${h.url_for( controller='dataset', action='show_params', dataset_id=trans.security.encode_id( hda.id ))}">${ hda.id | h }</a></td></tr>
@@ -47,7 +47,7 @@
%for j, table_row in enumerate( json_table ):
<tbody>
%if len_json_table > 1:
- <tr><td><strong>Entry #${j}</strong></td><td></td></tr>
+ <tr><td><strong>Entry #${j | h}</strong></td><td></td></tr>
%endif
%for name, value in table_row.iteritems():
<tr><td>${name | h}:</td><td>${value | h}</td></tr>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ed67b05dc040/
Changeset: ed67b05dc040
Branch: stable
User: dan
Date: 2014-12-04 21:14:28+00:00
Summary: Some web sanitization for Data Managers and Biostar redirect.
Affected #: 4 files
diff -r 9c482e1d9b3cfdb2936b3f230d434c1f27898eff -r ed67b05dc0402bf9ff9fbf35198ea2cac92e2c22 lib/galaxy/webapps/galaxy/controllers/data_manager.py
--- a/lib/galaxy/webapps/galaxy/controllers/data_manager.py
+++ b/lib/galaxy/webapps/galaxy/controllers/data_manager.py
@@ -7,6 +7,8 @@
pkg_resources.require( "Paste" )
import paste.httpexceptions
+from galaxy.web.framework.helpers import escape
+
#set up logger
import logging
log = logging.getLogger( __name__ )
@@ -18,8 +20,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
return trans.fill_template( "data_manager/index.mako", data_managers=trans.app.data_managers, tool_data_tables=trans.app.tool_data_tables, view_only=not_is_admin, message=message, status=status )
@web.expose
@@ -27,8 +29,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_manager_id = kwd.get( 'id', None )
data_manager = trans.app.data_managers.get_manager( data_manager_id )
if data_manager is None:
@@ -41,8 +43,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
job_id = kwd.get( 'id', None )
try:
job_id = trans.security.decode_id( job_id )
@@ -62,7 +64,7 @@
data_manager_json = loads( open( hda.get_file_name() ).read() )
except Exception, e:
data_manager_json = {}
- error_messages.append( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) )
+ error_messages.append( escape( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) ) )
values = []
for key, value in data_manager_json.get( 'data_tables', {} ).iteritems():
values.append( ( key, value ) )
@@ -74,8 +76,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_table_name = kwd.get( 'table_name', None )
if not data_table_name:
return trans.response.send_redirect( web.url_for( controller="data_manager", action="index" ) )
diff -r 9c482e1d9b3cfdb2936b3f230d434c1f27898eff -r ed67b05dc0402bf9ff9fbf35198ea2cac92e2c22 templates/webapps/galaxy/biostar/post_redirect.mako
--- a/templates/webapps/galaxy/biostar/post_redirect.mako
+++ b/templates/webapps/galaxy/biostar/post_redirect.mako
@@ -18,7 +18,7 @@
<p>If you are not automatically forwarded, click the button below:<p><form id="postRedirectForm" action="${post_url}" method="post" >
%for input_name, input_value in form_inputs.items():
- <input type="hidden" name="${input_name}" value="${input_value | h}">
+ <input type="hidden" name="${input_name | h}" value="${input_value | h}">
%endfor
<input type="submit" name="GalaxySubmitPostRedirectForm" id='GalaxySubmitPostRedirectForm' value="Click Here"></form>
diff -r 9c482e1d9b3cfdb2936b3f230d434c1f27898eff -r ed67b05dc0402bf9ff9fbf35198ea2cac92e2c22 templates/webapps/galaxy/data_manager/manage_data_table.mako
--- a/templates/webapps/galaxy/data_manager/manage_data_table.mako
+++ b/templates/webapps/galaxy/data_manager/manage_data_table.mako
@@ -14,9 +14,9 @@
<% column_name_list = data_table.get_column_name_list() %><table class="tabletip"><thead>
- <tr><th colspan="${len (column_name_list) }" style="font-size: 120%;">
+ <tr><th colspan="${ len( column_name_list ) | h}" style="font-size: 120%;">
Data Manager: ${ data_table.name | h }
- <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name} tool data table" data-placement="bottom">
+ <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name | h} tool data table" data-placement="bottom"><span class="fa fa-refresh"></span></a></th></tr>
diff -r 9c482e1d9b3cfdb2936b3f230d434c1f27898eff -r ed67b05dc0402bf9ff9fbf35198ea2cac92e2c22 templates/webapps/galaxy/data_manager/view_job.mako
--- a/templates/webapps/galaxy/data_manager/view_job.mako
+++ b/templates/webapps/galaxy/data_manager/view_job.mako
@@ -26,8 +26,8 @@
</thead><tbody><tr><td>Name:</td><td>${hda.name | h}</td></tr>
- <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format)}</td></tr>
- <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size)}</td></tr>
+ <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format) | h}</td></tr>
+ <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size) | h}</td></tr><tr><td>Tool Exit Code:</td><td>${job.exit_code | h}</td></tr><tr><td>Full Path:</td><td>${hda.file_name | h}</td></tr><tr><td>View complete info:</td><td><a href="${h.url_for( controller='dataset', action='show_params', dataset_id=trans.security.encode_id( hda.id ))}">${ hda.id | h }</a></td></tr>
@@ -47,7 +47,7 @@
%for j, table_row in enumerate( json_table ):
<tbody>
%if len_json_table > 1:
- <tr><td><strong>Entry #${j}</strong></td><td></td></tr>
+ <tr><td><strong>Entry #${j | h}</strong></td><td></td></tr>
%endif
%for name, value in table_row.iteritems():
<tr><td>${name | h}:</td><td>${value | h}</td></tr>
https://bitbucket.org/galaxy/galaxy-central/commits/de92a7b85033/
Changeset: de92a7b85033
Branch: stable
User: martenson
Date: 2014-12-05 16:49:14+00:00
Summary: Merged in dan/galaxy-central-prs/stable (pull request #593)
[STABLE] Some web sanitization for Data Managers and Biostar redirect.
Affected #: 4 files
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 lib/galaxy/webapps/galaxy/controllers/data_manager.py
--- a/lib/galaxy/webapps/galaxy/controllers/data_manager.py
+++ b/lib/galaxy/webapps/galaxy/controllers/data_manager.py
@@ -7,6 +7,8 @@
pkg_resources.require( "Paste" )
import paste.httpexceptions
+from galaxy.web.framework.helpers import escape
+
#set up logger
import logging
log = logging.getLogger( __name__ )
@@ -18,8 +20,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
return trans.fill_template( "data_manager/index.mako", data_managers=trans.app.data_managers, tool_data_tables=trans.app.tool_data_tables, view_only=not_is_admin, message=message, status=status )
@web.expose
@@ -27,8 +29,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_manager_id = kwd.get( 'id', None )
data_manager = trans.app.data_managers.get_manager( data_manager_id )
if data_manager is None:
@@ -41,8 +43,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
job_id = kwd.get( 'id', None )
try:
job_id = trans.security.decode_id( job_id )
@@ -62,7 +64,7 @@
data_manager_json = loads( open( hda.get_file_name() ).read() )
except Exception, e:
data_manager_json = {}
- error_messages.append( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) )
+ error_messages.append( escape( "Unable to obtain data_table info for hda (%s): %s" % ( hda.id, e ) ) )
values = []
for key, value in data_manager_json.get( 'data_tables', {} ).iteritems():
values.append( ( key, value ) )
@@ -74,8 +76,8 @@
not_is_admin = not trans.user_is_admin()
if not_is_admin and not trans.app.config.enable_data_manager_user_view:
raise paste.httpexceptions.HTTPUnauthorized( "This Galaxy instance is not configured to allow non-admins to view the data manager." )
- message = kwd.get( 'message' )
- status = kwd.get( 'status', 'info' )
+ message = escape( kwd.get( 'message', '' ) )
+ status = escape( kwd.get( 'status', 'info' ) )
data_table_name = kwd.get( 'table_name', None )
if not data_table_name:
return trans.response.send_redirect( web.url_for( controller="data_manager", action="index" ) )
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/biostar/post_redirect.mako
--- a/templates/webapps/galaxy/biostar/post_redirect.mako
+++ b/templates/webapps/galaxy/biostar/post_redirect.mako
@@ -18,7 +18,7 @@
<p>If you are not automatically forwarded, click the button below:<p><form id="postRedirectForm" action="${post_url}" method="post" >
%for input_name, input_value in form_inputs.items():
- <input type="hidden" name="${input_name}" value="${input_value | h}">
+ <input type="hidden" name="${input_name | h}" value="${input_value | h}">
%endfor
<input type="submit" name="GalaxySubmitPostRedirectForm" id='GalaxySubmitPostRedirectForm' value="Click Here"></form>
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/data_manager/manage_data_table.mako
--- a/templates/webapps/galaxy/data_manager/manage_data_table.mako
+++ b/templates/webapps/galaxy/data_manager/manage_data_table.mako
@@ -14,9 +14,9 @@
<% column_name_list = data_table.get_column_name_list() %><table class="tabletip"><thead>
- <tr><th colspan="${len (column_name_list) }" style="font-size: 120%;">
+ <tr><th colspan="${ len( column_name_list ) | h}" style="font-size: 120%;">
Data Manager: ${ data_table.name | h }
- <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name} tool data table" data-placement="bottom">
+ <a class="icon-btn" href="${ h.url_for( controller="data_manager", action="reload_tool_data_tables", table_name=data_table.name ) }" title="Reload ${data_table.name | h} tool data table" data-placement="bottom"><span class="fa fa-refresh"></span></a></th></tr>
diff -r 295fd99b1d578e4d58af673259b95e703750f757 -r de92a7b850332c0d3c8ef393c1ff0db98f4b37f7 templates/webapps/galaxy/data_manager/view_job.mako
--- a/templates/webapps/galaxy/data_manager/view_job.mako
+++ b/templates/webapps/galaxy/data_manager/view_job.mako
@@ -26,8 +26,8 @@
</thead><tbody><tr><td>Name:</td><td>${hda.name | h}</td></tr>
- <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format)}</td></tr>
- <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size)}</td></tr>
+ <tr><td>Created:</td><td>${hda.create_time.strftime(trans.app.config.pretty_datetime_format) | h}</td></tr>
+ <tr><td>Filesize:</td><td>${nice_size(hda.dataset.file_size) | h}</td></tr><tr><td>Tool Exit Code:</td><td>${job.exit_code | h}</td></tr><tr><td>Full Path:</td><td>${hda.file_name | h}</td></tr><tr><td>View complete info:</td><td><a href="${h.url_for( controller='dataset', action='show_params', dataset_id=trans.security.encode_id( hda.id ))}">${ hda.id | h }</a></td></tr>
@@ -47,7 +47,7 @@
%for j, table_row in enumerate( json_table ):
<tbody>
%if len_json_table > 1:
- <tr><td><strong>Entry #${j}</strong></td><td></td></tr>
+ <tr><td><strong>Entry #${j | h}</strong></td><td></td></tr>
%endif
%for name, value in table_row.iteritems():
<tr><td>${name | h}:</td><td>${value | h}</td></tr>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Improvements to to yaml_to_workflow for Kyle.
by commits-noreply@bitbucket.org 04 Dec '14
by commits-noreply@bitbucket.org 04 Dec '14
04 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/46a3d43d779f/
Changeset: 46a3d43d779f
User: jmchilton
Date: 2014-12-04 21:18:20+00:00
Summary: Improvements to to yaml_to_workflow for Kyle.
Add UUID to workflows (his contribution) - add shortcuts for rename an hide actions with tests (his request, my implementation).
Affected #: 4 files
diff -r 7272cc7b9ea1fd64646fa6d7e6fb5924fd8618f8 -r 46a3d43d779fa7735029449935dad77474adf9b1 test/api/test_workflow_extraction.py
--- a/test/api/test_workflow_extraction.py
+++ b/test/api/test_workflow_extraction.py
@@ -182,68 +182,6 @@
collection_step_state = loads( collection_step[ "tool_state" ] )
self.assertEquals( collection_step_state[ "collection_type" ], u"list:paired" )
- def _run_jobs( self, jobs_yaml ):
- history_id = self.history_id
- workflow_id = self._upload_yaml_workflow(
- jobs_yaml
- )
- jobs_descriptions = yaml.load( jobs_yaml )
- test_data = jobs_descriptions["test_data"]
-
- label_map = {}
- inputs = {}
- for key, value in test_data.items():
- if isinstance( value, dict ):
- elements_data = value.get( "elements", [] )
- elements = []
- for element_data in elements_data:
- identifier = element_data[ "identifier" ]
- content = element_data["content"]
- elements.append( ( identifier, content ) )
- collection_type = value["type"]
- if collection_type == "list:paired":
- hdca = self.dataset_collection_populator.create_list_of_pairs_in_history( history_id ).json()
- elif collection_type == "list":
- hdca = self.dataset_collection_populator.create_list_in_history( history_id, contents=elements ).json()
- else:
- hdca = self.dataset_collection_populator.create_pair_in_history( history_id, contents=elements ).json()
- label_map[key] = self._ds_entry( hdca )
- inputs[key] = hdca
- else:
- hda = self.dataset_populator.new_dataset( history_id, content=value )
- label_map[key] = self._ds_entry( hda )
- inputs[key] = hda
- workflow_request = dict(
- history="hist_id=%s" % history_id,
- workflow_id=workflow_id,
- )
- workflow_request[ "inputs" ] = dumps( label_map )
- workflow_request[ "inputs_by" ] = 'name'
- self.dataset_populator.wait_for_history( history_id, assert_ok=True )
- url = "workflows/%s/usage" % ( workflow_id )
- invocation_response = self._post( url, data=workflow_request )
- self._assert_status_code_is( invocation_response, 200 )
- invocation = invocation_response.json()
- invocation_id = invocation[ "id" ]
- # Wait for workflow to become fully scheduled and then for all jobs
- # complete.
- self.wait_for_invocation( workflow_id, invocation_id )
- self.dataset_populator.wait_for_history( history_id, assert_ok=True )
- jobs = self._history_jobs( history_id )
- return RunJobsSummary(
- history_id=history_id,
- workflow_id=workflow_id,
- inputs=inputs,
- jobs=jobs,
- )
-
- def wait_for_invocation( self, workflow_id, invocation_id ):
- url = "workflows/%s/usage/%s" % ( workflow_id, invocation_id )
- return wait_on_state( lambda: self._get( url ) )
-
- def _history_jobs( self, history_id ):
- return self._get("jobs", { "history_id": history_id, "order_by": "create_time" } ).json()
-
def _job_id_for_tool( self, jobs, tool_id ):
return self._job_for_tool( jobs, tool_id )[ "id" ]
diff -r 7272cc7b9ea1fd64646fa6d7e6fb5924fd8618f8 -r 46a3d43d779fa7735029449935dad77474adf9b1 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -1,6 +1,12 @@
+from .helpers import wait_on_state
+
from base import api
from json import dumps
+from collections import namedtuple
+
import time
+
+import yaml
from .helpers import WorkflowPopulator
from .helpers import DatasetPopulator
from .helpers import DatasetCollectionPopulator
@@ -101,6 +107,69 @@
invocation_details = invocation_details_response.json()
return invocation_details
+ def _run_jobs( self, jobs_yaml, history_id=None ):
+ if history_id is None:
+ history_id = self.history_id
+ workflow_id = self._upload_yaml_workflow(
+ jobs_yaml
+ )
+ jobs_descriptions = yaml.load( jobs_yaml )
+ test_data = jobs_descriptions["test_data"]
+
+ label_map = {}
+ inputs = {}
+ for key, value in test_data.items():
+ if isinstance( value, dict ):
+ elements_data = value.get( "elements", [] )
+ elements = []
+ for element_data in elements_data:
+ identifier = element_data[ "identifier" ]
+ content = element_data["content"]
+ elements.append( ( identifier, content ) )
+ collection_type = value["type"]
+ if collection_type == "list:paired":
+ hdca = self.dataset_collection_populator.create_list_of_pairs_in_history( history_id ).json()
+ elif collection_type == "list":
+ hdca = self.dataset_collection_populator.create_list_in_history( history_id, contents=elements ).json()
+ else:
+ hdca = self.dataset_collection_populator.create_pair_in_history( history_id, contents=elements ).json()
+ label_map[key] = self._ds_entry( hdca )
+ inputs[key] = hdca
+ else:
+ hda = self.dataset_populator.new_dataset( history_id, content=value )
+ label_map[key] = self._ds_entry( hda )
+ inputs[key] = hda
+ workflow_request = dict(
+ history="hist_id=%s" % history_id,
+ workflow_id=workflow_id,
+ )
+ workflow_request[ "inputs" ] = dumps( label_map )
+ workflow_request[ "inputs_by" ] = 'name'
+ self.dataset_populator.wait_for_history( history_id, assert_ok=True )
+ url = "workflows/%s/usage" % ( workflow_id )
+ invocation_response = self._post( url, data=workflow_request )
+ self._assert_status_code_is( invocation_response, 200 )
+ invocation = invocation_response.json()
+ invocation_id = invocation[ "id" ]
+ # Wait for workflow to become fully scheduled and then for all jobs
+ # complete.
+ self.wait_for_invocation( workflow_id, invocation_id )
+ self.dataset_populator.wait_for_history( history_id, assert_ok=True )
+ jobs = self._history_jobs( history_id )
+ return RunJobsSummary(
+ history_id=history_id,
+ workflow_id=workflow_id,
+ inputs=inputs,
+ jobs=jobs,
+ )
+
+ def wait_for_invocation( self, workflow_id, invocation_id ):
+ url = "workflows/%s/usage/%s" % ( workflow_id, invocation_id )
+ return wait_on_state( lambda: self._get( url ) )
+
+ def _history_jobs( self, history_id ):
+ return self._get("jobs", { "history_id": history_id, "order_by": "create_time" } ).json()
+
# Workflow API TODO:
# - Allow history_id as param to workflow run action. (hist_id)
@@ -641,3 +710,7 @@
shared_workflow_id=workflow_id,
)
return self._post( route, import_data )
+
+
+RunJobsSummary = namedtuple('RunJobsSummary', ['history_id', 'workflow_id', 'inputs', 'jobs'])
+
diff -r 7272cc7b9ea1fd64646fa6d7e6fb5924fd8618f8 -r 46a3d43d779fa7735029449935dad77474adf9b1 test/api/test_workflows_from_yaml.py
--- a/test/api/test_workflows_from_yaml.py
+++ b/test/api/test_workflows_from_yaml.py
@@ -1,4 +1,3 @@
-import json
from .test_workflows import BaseWorkflowsApiTestCase
@@ -30,3 +29,33 @@
__current_case__: 1
""")
self._get("workflows/%s/download" % workflow_id).content
+
+ def test_simple_output_actions( self ):
+ history_id = self.dataset_populator.new_history()
+ self._run_jobs("""
+steps:
+ - type: input
+ label: input1
+ - tool_id: cat1
+ label: first_cat
+ state:
+ input1:
+ $link: 0
+ outputs:
+ out_file1:
+ hide: true
+ rename: "the new value"
+ - tool_id: cat1
+ state:
+ input1:
+ $link: first_cat#out_file1
+test_data:
+ input1: "hello world"
+""", history_id=history_id)
+
+ details1 = self.dataset_populator.get_history_dataset_details(history_id, hid=2)
+ assert not details1["visible"]
+ assert details1["name"] == "the new value", details1
+ details2 = self.dataset_populator.get_history_dataset_details(history_id, hid=3)
+ assert details2["visible"]
+ assert False
diff -r 7272cc7b9ea1fd64646fa6d7e6fb5924fd8618f8 -r 46a3d43d779fa7735029449935dad77474adf9b1 test/api/yaml_to_workflow.py
--- a/test/api/yaml_to_workflow.py
+++ b/test/api/yaml_to_workflow.py
@@ -2,6 +2,7 @@
import yaml
import json
+import uuid
try:
from collections import OrderedDict
@@ -25,7 +26,8 @@
"a_galaxy_workflow": "true",
"format-version": "0.1",
"annotation": "",
- "name": "Workflow"
+ "name": "Workflow",
+ "uuid": str(uuid.uuid4()),
})
steps = as_python["steps"]
@@ -107,8 +109,10 @@
__ensure_defaults( step, {
"annotation": "",
+ "post_job_actions": {},
} )
__ensure_inputs_connections(step)
+ post_job_actions = step["post_job_actions"]
tool_state = {
# TODO: Galaxy should not require tool state actually specify a __page__.
@@ -178,6 +182,30 @@
__populate_tool_state(step, tool_state)
+ # Handle outputs.
+ if "outputs" in step:
+ for name, output in step.get("outputs", {}).items():
+ if output.get("hide", False):
+ action_name = "HideDatasetAction%s" % name
+ action = __action(
+ "HideDatasetAction",
+ name,
+ )
+ post_job_actions[action_name] = action
+
+ if output.get("rename", None):
+ new_name = output.get("rename")
+ action_name = "RenameDatasetAction%s" % name
+ arguments = dict(newname=new_name)
+ action = __action(
+ "RenameDatasetAction",
+ name,
+ arguments,
+ )
+ post_job_actions[action_name] = action
+
+ del step["outputs"]
+
class ConversionContext(object):
@@ -185,6 +213,14 @@
self.labels = {}
+def __action(type, name, arguments={}):
+ return {
+ "action_arguments": arguments,
+ "action_type": type,
+ "output_name": name,
+ }
+
+
def __is_link(value):
return isinstance(value, dict) and "$link" in value
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0