# HG changeset patch --
Bitbucket.org
# Project galaxy-dist
# URL
http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1283450357 14400
# Node ID f09915c8da9404b8642b96ee81d89afdccde8414
# Parent 121678c8a483061c531c37c8d2e398ae1baa315a
Library template improvements and miscellaneous fixes:
1. Add support for handling inherited library temnplates that include all supported field
types ( AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField ) to
the upload form for library datasets. New userAddress objects can now be created on the
upload forms.
2. Improve the UI for selecting tempaltes for library items - it is now clear that the
displayed template is not useable since it is disabled and a message is displayed.
3. Automatically inherit template contents from parent for inherited templates.
4. Fix the AddressField UI to display the required fields for rendered html.
5. Add new test_library_templates.py functional test script.
.
--- /dev/null
+++ b/test/functional/test_library_templates.py
@@ -0,0 +1,219 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestLibraryFeatures( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu', username='regular-user1' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email
"test1(a)bx.psu.edu" from the database'
+ global regular_user1_private_role
+ regular_user1_private_role = get_private_role( regular_user1 )
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu', username='regular-user2' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email
"test2(a)bx.psu.edu" from the database'
+ global regular_user2_private_role
+ regular_user2_private_role = get_private_role( regular_user2 )
+ self.logout()
+ self.login( email='test3(a)bx.psu.edu', username='regular-user3' )
+ global regular_user3
+ regular_user3 = get_user( 'test3(a)bx.psu.edu' )
+ assert regular_user3 is not None, 'Problem retrieving user with email
"test3(a)bx.psu.edu" from the database'
+ global regular_user3_private_role
+ regular_user3_private_role = get_private_role( regular_user3 )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu', username='admin-user' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email
"test(a)bx.psu.edu" from the database'
+ global admin_user_private_role
+ admin_user_private_role = get_private_role( admin_user )
+ def test_005_create_library_templates( self ):
+ """Testing creating several LibraryInformationTemplate form
definitions"""
+ # Logged in as admin_user
+ for type in [ 'AddressField', 'CheckboxField',
'SelectField', 'TextArea', 'TextField', 'WorkflowField'
]:
+ form_desc = '%s description' % type
+ # Create form for library template
+ self.create_single_field_type_form_definition( name=type,
+ desc=form_desc,
+
formtype=galaxy.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE,
+ field_type=type )
+ # Get all of the new form definitions for later use
+ global AddressField_form
+ AddressField_form = get_form( 'AddressField' )
+ global CheckboxField_form
+ CheckboxField_form = get_form( 'CheckboxField' )
+ global SelectField_form
+ SelectField_form = get_form( 'SelectField' )
+ global TextArea_form
+ TextArea_form = get_form( 'TextArea' )
+ global TextField_form
+ TextField_form = get_form( 'TextField' )
+ global WorkflowField_form
+ WorkflowField_form = get_form( 'WorkflowField' )
+ def test_010_create_libraries( self ):
+ """Testing creating a new library for each
template"""
+ # Logged in as admin_user
+ for index, form in enumerate( [ AddressField_form, CheckboxField_form,
SelectField_form, TextArea_form, TextField_form, WorkflowField_form ] ):
+ name = 'library%s' % str( index + 1 )
+ description = '%s description' % name
+ synopsis = '%s synopsis' % name
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ # Get the libraries for later use
+ global library1
+ library1 = get_library( 'library1', 'library1 description',
'library1 synopsis' )
+ global library2
+ library2 = get_library( 'library2', 'library2 description',
'library2 synopsis' )
+ global library3
+ library3 = get_library( 'library3', 'library3 description',
'library3 synopsis' )
+ global library4
+ library4 = get_library( 'library4', 'library4 description',
'library4 synopsis' )
+ global library5
+ library5 = get_library( 'library5', 'library5 description',
'library5 synopsis' )
+ global library6
+ library6 = get_library( 'library6', 'library6 description',
'library6 synopsis' )
+ def test_015_add_template_to_library1( self ):
+ """Testing add an inheritable template containing an AddressField
to library1"""
+ # Logged in as admin_user
+ # Add a template to library1
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( AddressField_form.id ),
+ AddressField_form.name )
+ def test_020_add_folder_to_library1( self ):
+ """Testing adding a root folder to library1"""
+ # Logged in as admin_user
+ # Add a root folder to library1
+ folder = library1.root_folder
+ name = "folder"
+ description = "folder description"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( folder.id ),
+ name=name,
+ description=description )
+ global folder1
+ folder1 = get_folder( folder.id, name, description )
+ def test_025_check_library1( self ):
+ """Checking library1 and its root folder"""
+ # Logged in as admin_user
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library1.id ),
+ check_str1=folder1.name,
+ check_str2=folder1.description )
+ # Make sure the template and contents were inherited to folder1
+ self.folder_info( 'library_admin',
+ self.security.encode_id( folder1.id ),
+ self.security.encode_id( library1.id ),
+ check_str1=AddressField_form.name,
+ check_str2='This is an inherited template and is not
required to be used with this folder' )
+ def test_030_add_dataset_to_library1_root_folder( self ):
+ """
+ Testing adding a new library dataset to library1's root folder, and adding a
new UserAddress
+ on the upload form.
+ """
+ # Logged in as admin_user
+ # The AddressField template should be inherited to the library dataset upload
form. Passing
+ # the value 'new' should submit the form via refresh_on_change and allow
new UserAddress information
+ # to be posted as part of the upload.
+ self.add_library_dataset( 'library_admin',
+ '1.bed',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( library1.root_folder.id ),
+ library1.root_folder.name,
+ file_type='bed',
+ dbkey='hg18',
+ root=True,
+ template_refresh_field_name='field_0',
+ template_refresh_field_contents='new',
+ field_0_short_desc='Office',
+ field_0_name='Dick',
+ field_0_institution='PSU',
+ field_0_address='32 O Street',
+ field_0_city='Anywhere',
+ field_0_state='AK',
+ field_0_postal_code='0000000',
+ field_0_country='USA' )
+ global ldda1
+ ldda1 = get_latest_ldda()
+ assert ldda1 is not None, 'Problem retrieving
LibraryDatasetDatasetAssociation ldda1 from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library1.id ),
+ check_str1='1.bed',
+ check_str2=admin_user.email )
+ # Make sure the library template contents were correctly saved
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library1.id ),
+ self.security.encode_id( library1.root_folder.id ),
+ self.security.encode_id( ldda1.id ),
+ ldda1.name,
+ check_str1='Dick' )
+ def test_035_add_template_to_library2( self ):
+ """ Testing add an inheritable template containing an
CheckboxField to library2"""
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library2.id ),
+ self.security.encode_id( CheckboxField_form.id ),
+ CheckboxField_form.name )
+ def test_040_add_template_to_library3( self ):
+ """ Testing add an inheritable template containing an SelectField
to library3"""
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library3.id ),
+ self.security.encode_id( SelectField_form.id ),
+ SelectField_form.name )
+ def test_045_add_template_to_library4( self ):
+ """ Testing add an inheritable template containing an TextArea to
library4"""
+ # Add an inheritable template to library4
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library4.id ),
+ self.security.encode_id( TextArea_form.id ),
+ TextArea_form.name )
+ def test_050_add_template_to_library5( self ):
+ """ Testing add an inheritable template containing an TextField to
library5"""
+ # Add an inheritable template to library5
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library5.id ),
+ self.security.encode_id( TextField_form.id ),
+ TextField_form.name )
+ def test_055_add_template_to_library6( self ):
+ """ Testing add an inheritable template containing an
WorkflowField to library6"""
+ # Add an inheritable template to library6
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library6.id ),
+ self.security.encode_id( WorkflowField_form.id ),
+ WorkflowField_form.name )
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to
pass"""
+ # Logged in as admin_user
+ ##################
+ # Delete all form definitions
+ ##################
+ for form in [ AddressField_form, CheckboxField_form, SelectField_form,
TextArea_form, TextField_form, WorkflowField_form ]:
+ self.mark_form_deleted( self.security.encode_id(
form.form_definition_current.id ) )
+ ##################
+ # Purge all libraries
+ ##################
+ for library in [ library1, library2, library3, library4, library5, library6 ]:
+ self.delete_library_item( 'library_admin',
+ self.security.encode_id( library.id ),
+ self.security.encode_id( library.id ),
+ library.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library.id ), library.name )
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s
( should be 1 )' % ( len( user.roles ), user.email ) )
+ self.logout()
--- a/lib/galaxy/web/form_builder.py
+++ b/lib/galaxy/web/form_builder.py
@@ -4,12 +4,19 @@ Classes for generating HTML forms
import logging,sys
from cgi import escape
+from galaxy.util import restore_text
+
log = logging.getLogger(__name__)
class BaseField(object):
def get_html( self, prefix="" ):
"""Returns the html widget corresponding to the
parameter"""
raise TypeError( "Abstract Method" )
+ def get_disabled_str( self, disabled=False ):
+ if disabled:
+ return 'disabled="disabled"'
+ else:
+ return ''
@staticmethod
def form_field_types():
return ['TextField', 'TextArea', 'SelectField',
'CheckboxField', 'AddressField', 'WorkflowField']
@@ -31,9 +38,9 @@ class TextField(BaseField):
self.name = name
self.size = int( size or 10 )
self.value = value or ""
- def get_html( self, prefix="" ):
- return '<input type="text" name="%s%s"
size="%d" value="%s">' \
- % ( prefix, self.name, self.size, escape(str(self.value), quote=True) )
+ def get_html( self, prefix="", disabled=False ):
+ return '<input type="text" name="%s%s"
size="%d" value="%s" %s>' \
+ % ( prefix, self.name, self.size, escape( str( self.value ), quote=True ),
self.get_disabled_str( disabled ) )
def set_size(self, size):
self.size = int( size )
@@ -52,7 +59,7 @@ class PasswordField(BaseField):
self.value = value or ""
def get_html( self, prefix="" ):
return '<input type="password" name="%s%s"
size="%d" value="%s">' \
- % ( prefix, self.name, self.size, escape(str(self.value), quote=True) )
+ % ( prefix, self.name, self.size, escape( str( self.value ), quote=True ) )
def set_size(self, size):
self.size = int( size )
@@ -71,9 +78,9 @@ class TextArea(BaseField):
self.rows = int(self.size[0])
self.cols = int(self.size[-1])
self.value = value or ""
- def get_html( self, prefix="" ):
- return '<textarea name="%s%s" rows="%d"
cols="%d">%s</textarea>' \
- % ( prefix, self.name, self.rows, self.cols, escape( str( self.value ),
quote=True ) )
+ def get_html( self, prefix="", disabled=False ):
+ return '<textarea name="%s%s" rows="%d"
cols="%d" %s>%s</textarea>' \
+ % ( prefix, self.name, self.rows, self.cols, self.get_disabled_str( disabled
), escape( str( self.value ), quote=True ) )
def set_size(self, rows, cols):
self.rows = rows
self.cols = cols
@@ -90,7 +97,7 @@ class CheckboxField(BaseField):
def __init__( self, name, checked=None ):
self.name = name
self.checked = ( checked == True ) or ( isinstance( checked, basestring ) and (
checked.lower() in ( "yes", "true", "on" ) ) )
- def get_html( self, prefix="" ):
+ def get_html( self, prefix="", disabled=False ):
if self.checked:
checked_text = "checked"
else:
@@ -100,8 +107,8 @@ class CheckboxField(BaseField):
# parsing the request, the value 'true' in the hidden field actually
means it is NOT checked.
# See the is_checked() method below. The prefix is necessary in each case to
ensure functional
# correctness when the param is inside a conditional.
- return '<input type="checkbox" name="%s%s"
value="true" %s><input type="hidden" name="%s%s"
value="true">' \
- % ( prefix, self.name, checked_text, prefix, self.name )
+ return '<input type="checkbox" name="%s%s"
value="true" %s %s><input type="hidden" name="%s%s"
value="true" %s>' \
+ % ( prefix, self.name, checked_text, self.get_disabled_str( disabled ),
prefix, self.name, self.get_disabled_str( disabled ) )
@staticmethod
def is_checked( value ):
if value == True:
@@ -150,7 +157,7 @@ class HiddenField(BaseField):
self.name = name
self.value = value or ""
def get_html( self, prefix="" ):
- return '<input type="hidden" name="%s%s"
value="%s">' % ( prefix, self.name, escape(str(self.value), quote=True)
)
+ return '<input type="hidden" name="%s%s"
value="%s">' % ( prefix, self.name, escape( str( self.value ), quote=True
) )
class SelectField(BaseField):
"""
@@ -210,14 +217,14 @@ class SelectField(BaseField):
self.refresh_on_change_text = ''
def add_option( self, text, value, selected = False ):
self.options.append( ( text, value, selected ) )
- def get_html( self, prefix="" ):
+ def get_html( self, prefix="", disabled=False ):
if self.display == "checkboxes":
- return self.get_html_checkboxes( prefix )
+ return self.get_html_checkboxes( prefix, disabled )
elif self.display == "radio":
- return self.get_html_radio( prefix )
+ return self.get_html_radio( prefix, disabled )
else:
- return self.get_html_default( prefix )
- def get_html_checkboxes( self, prefix="" ):
+ return self.get_html_default( prefix, disabled )
+ def get_html_checkboxes( self, prefix="", disabled=False ):
rval = []
ctr = 0
if len( self.options ) > 1:
@@ -227,12 +234,14 @@ class SelectField(BaseField):
if len(self.options) > 2 and ctr % 2 == 1:
style = " class=\"odd_row\""
if selected:
- rval.append( '<div%s><input type="checkbox"
name="%s%s" value="%s" checked>%s</div>' % ( style,
prefix, self.name, escape(str(value), quote=True), text) )
+ rval.append( '<div%s><input type="checkbox"
name="%s%s" value="%s" checked %s>%s</div>' % \
+ ( style, prefix, self.name, escape( str( value ), quote=True
), self.get_disabled_str( disabled ), text ) )
else:
- rval.append( '<div%s><input type="checkbox"
name="%s%s" value="%s">%s</div>' % ( style, prefix,
self.name, escape(str(value), quote=True), text) )
+ rval.append( '<div%s><input type="checkbox"
name="%s%s" value="%s" %s>%s</div>' % \
+ ( style, prefix, self.name, escape( str( value ), quote=True
), self.get_disabled_str( disabled ), text ) )
ctr += 1
return "\n".join( rval )
- def get_html_radio( self, prefix="" ):
+ def get_html_radio( self, prefix="", disabled=False ):
rval = []
ctr = 0
for text, value, selected in self.options:
@@ -241,11 +250,20 @@ class SelectField(BaseField):
style = " class=\"odd_row\""
if selected: selected_text = " checked"
else: selected_text = ""
- rval.append( '<div%s><input type="radio"
name="%s%s"%s value="%s"%s>%s</div>' % ( style, prefix,
self.name, self.refresh_on_change_text, escape(str(value), quote=True), selected_text,
text ) )
+ rval.append( '<div%s><input type="radio"
name="%s%s"%s value="%s"%s %s>%s</div>' % \
+ ( style,
+ prefix,
+ self.name,
+ self.refresh_on_change_text,
+ escape( str( value ), quote=True ),
+ selected_text,
+ self.get_disabled_str( disabled ),
+ text ) )
ctr += 1
return "\n".join( rval )
- def get_html_default( self, prefix="" ):
- if self.multiple: multiple = " multiple"
+ def get_html_default( self, prefix="", disabled=False ):
+ if self.multiple:
+ multiple = " multiple"
else: multiple = ""
rval = []
last_selected_value = ""
@@ -253,11 +271,13 @@ class SelectField(BaseField):
if selected:
selected_text = " selected"
last_selected_value = value
- else: selected_text = ""
- rval.append( '<option value="%s"%s>%s</option>'
% ( escape(str(value), quote=True), selected_text, text ) )
+ else:
+ selected_text = ""
+ rval.append( '<option value="%s"%s>%s</option>'
% ( escape( str( value ), quote=True ), selected_text, text ) )
if last_selected_value:
- last_selected_value = ' last_selected_value="%s"' %
escape(str(last_selected_value), quote=True)
- rval.insert( 0, '<select name="%s%s"%s%s%s>' % ( prefix,
self.name, multiple, self.refresh_on_change_text, last_selected_value ) )
+ last_selected_value = ' last_selected_value="%s"' % escape(
str( last_selected_value ), quote=True )
+ rval.insert( 0, '<select name="%s%s"%s%s%s %s>' % \
+ ( prefix, self.name, multiple, self.refresh_on_change_text,
last_selected_value, self.get_disabled_str( disabled ), ) )
rval.append( '</select>' )
return "\n".join( rval )
def get_selected(self):
@@ -381,61 +401,71 @@ class DrillDownField( BaseField ):
class AddressField(BaseField):
@staticmethod
def fields():
- return [ ( "short_desc", "Short address description"),
- ( "name", "Name" ),
- ( "institution", "Institution" ),
- ( "address", "Address" ),
- ( "city", "City" ),
- ( "state", "State/Province/Region" ),
- ( "postal_code", "Postal Code" ),
- ( "country", "Country" ),
- ( "phone", "Phone" ) ]
+ return [ ( "short_desc", "Short address description",
"Required" ),
+ ( "name", "Name", "Required" ),
+ ( "institution", "Institution",
"Required" ),
+ ( "address", "Address", "Required" ),
+ ( "city", "City", "Required" ),
+ ( "state", "State/Province/Region",
"Required" ),
+ ( "postal_code", "Postal Code",
"Required" ),
+ ( "country", "Country", "Required" ),
+ ( "phone", "Phone", "" ) ]
def __init__(self, name, user=None, value=None, params=None):
self.name = name
self.user = user
self.value = value
self.select_address = None
self.params = params
- def get_html(self):
- from galaxy import util
+ def get_html( self, disabled=False ):
address_html = ''
add_ids = ['none']
if self.user:
for a in self.user.addresses:
- add_ids.append(str(a.id))
- add_ids.append('new')
- self.select_address = SelectField(self.name,
- refresh_on_change=True,
- refresh_on_change_values=add_ids)
+ add_ids.append( str( a.id ) )
+ add_ids.append( 'new' )
+ self.select_address = SelectField( self.name,
+ refresh_on_change=True,
+ refresh_on_change_values=add_ids )
if self.value == 'none':
- self.select_address.add_option('Select one', 'none',
selected=True)
+ self.select_address.add_option( 'Select one', 'none',
selected=True )
else:
- self.select_address.add_option('Select one', 'none')
+ self.select_address.add_option( 'Select one', 'none' )
if self.user:
for a in self.user.addresses:
if not a.deleted:
- if self.value == str(a.id):
- self.select_address.add_option(a.desc, str(a.id), selected=True)
- # display this address
- address_html = '''<div
class="form-row">
- %s
- </div>''' % a.get_html()
+ if self.value == str( a.id ):
+ self.select_address.add_option( a.desc, str( a.id ),
selected=True )
+ # Display this address
+ address_html += '''
+ <div class="form-row">
+ %s
+ </div>
+ ''' % a.get_html()
else:
- self.select_address.add_option(a.desc, str(a.id))
+ self.select_address.add_option( a.desc, str( a.id ) )
if self.value == 'new':
- self.select_address.add_option('Add a new address', 'new',
selected=True)
- for field_name, label in self.fields():
- add_field = TextField(self.name+'_'+field_name,
+ self.select_address.add_option( 'Add a new address', 'new',
selected=True )
+ for field_name, label, help_text in self.fields():
+ add_field = TextField( self.name + '_' + field_name,
40,
- util.restore_text( self.params.get(
self.name+'_'+field_name, '' ) ))
- address_html += ''' <div class="form-row">
- <label>%s</label>
+ restore_text( self.params.get( self.name +
'_' + field_name, '' ) ) )
+ address_html += '''
+ <div class="form-row">
+ <label>%s</label>
+ %s
+ ''' % ( label, add_field.get_html(
disabled=disabled ) )
+ if help_text:
+ address_html += '''
+ <div class="toolParamHelp"
style="clear: both;">
%s
</div>
- ''' % (label, add_field.get_html())
+ ''' % help_text
+ address_html += '''
+ </div>
+ '''
else:
- self.select_address.add_option('Add a new address', 'new')
- return self.select_address.get_html()+address_html
+ self.select_address.add_option( 'Add a new address', 'new' )
+ return self.select_address.get_html( disabled=disabled ) + address_html
class WorkflowField(BaseField):
def __init__(self, name, user=None, value=None, params=None):
@@ -444,21 +474,20 @@ class WorkflowField(BaseField):
self.value = value
self.select_workflow = None
self.params = params
- def get_html(self):
- self.select_workflow = SelectField(self.name)
+ def get_html( self, disabled=False ):
+ self.select_workflow = SelectField( self.name )
if self.value == 'none':
- self.select_workflow.add_option('Select one', 'none',
selected=True)
+ self.select_workflow.add_option( 'Select one', 'none',
selected=True )
else:
- self.select_workflow.add_option('Select one', 'none')
+ self.select_workflow.add_option( 'Select one', 'none' )
if self.user:
for a in self.user.stored_workflows:
if not a.deleted:
- if str(self.value) == str(a.id):
- self.select_workflow.add_option(a.name, str(a.id),
selected=True)
+ if str( self.value ) == str( a.id ):
+ self.select_workflow.add_option( a.name, str( a.id ),
selected=True )
else:
- self.select_workflow.add_option(a.name, str(a.id))
- return self.select_workflow.get_html()
-
+ self.select_workflow.add_option( a.name, str( a.id ) )
+ return self.select_workflow.get_html( disabled=disabled )
def get_suite():
"""Get unittest suite for this module"""
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -313,9 +313,9 @@ class UsesFormDefinitionWidgets:
return True
if isinstance( field[ 'widget' ], CheckboxField ) and field[
'widget' ].checked:
return True
- if isinstance( field[ 'widget' ], WorkflowField ) and field[
'widget' ].value not in [ 'none', 'None', None ]:
+ if isinstance( field[ 'widget' ], WorkflowField ) and str( field[
'widget' ].value ).lower() not in [ 'none' ]:
return True
- if isinstance( field[ 'widget' ], AddressField ) and field[
'widget' ].value not in [ 'none', 'None', None ]:
+ if isinstance( field[ 'widget' ], AddressField ) and str( field[
'widget' ].value ).lower() not in [ 'none' ]:
return True
return False
def clean_field_contents( self, widgets, **kwd ):
@@ -332,9 +332,24 @@ class UsesFormDefinitionWidgets:
field_value = widget.value
field_contents.append( util.restore_text( field_value ) )
return field_contents
+ def field_param_values_ok( self, index, widget_type, **kwd ):
+ # Make sure required fields have contents, etc
+ # TODO: Add support for other field types ( e.g., WorkflowField, etc )
+ params = util.Params( kwd )
+ if widget_type == 'AddressField':
+ if not util.restore_text( params.get( 'field_%i_short_desc' % index,
'' ) ) \
+ or not util.restore_text( params.get( 'field_%i_name' % index,
'' ) ) \
+ or not util.restore_text( params.get( 'field_%i_institution' %
index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_address' % index,
'' ) ) \
+ or not util.restore_text( params.get( 'field_%i_city' % index,
'' ) ) \
+ or not util.restore_text( params.get( 'field_%i_state' % index,
'' ) ) \
+ or not util.restore_text( params.get( 'field_%i_postal_code' %
index, '' ) ) \
+ or not util.restore_text( params.get( 'field_%i_country' % index,
'' ) ):
+ return False
+ return True
def save_widget_field( self, trans, field_obj, index, **kwd ):
# Save a form_builder field object
- # TODO: Add support for other field types ( e.g., WorkflowField )
+ # TODO: Add support for other field types ( e.g., WorkflowField, etc )
params = util.Params( kwd )
if isinstance( field_obj, trans.model.UserAddress ):
field_obj.desc = util.restore_text( params.get( 'field_%i_short_desc'
% index, '' ) )
@@ -1227,6 +1242,7 @@ class Admin( object ):
# - Dataset where HistoryDatasetAssociation.dataset_id = Dataset.id
# - UserGroupAssociation where user_id == User.id
# - UserRoleAssociation where user_id == User.id EXCEPT FOR THE PRIVATE ROLE
+ # - UserAddress where user_id == User.id
# Purging Histories and Datasets must be handled via the cleanup_datasets.py
script
webapp = kwd.get( 'webapp', 'galaxy' )
id = kwd.get( 'id', None )
@@ -1271,6 +1287,9 @@ class Admin( object ):
for ura in user.roles:
if ura.role_id != private_role.id:
trans.sa_session.delete( ura )
+ # Delete UserAddresses
+ for address in user.addresses:
+ trans.sa_session.delete( address )
# Purge the user
user.purged = True
trans.sa_session.add( user )
--- a/templates/library/common/upload.mako
+++ b/templates/library/common/upload.mako
@@ -12,8 +12,32 @@
%><%def name="javascripts()">
+ ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
${parent.javascripts()}
- ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
+ <script type="text/javascript">
+ $( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem(
'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split(
',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem(
'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || (
last_selected_value && last_selected_value.value == refresh_on_change_values[i] )
){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#upload_library_dataset" ).submit();
+ }
+ });
+ });
+ </script></%def><%def name="stylesheets()">
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -862,7 +862,8 @@ class Library( object ):
# inherited is not applicable at the library level. The get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form, but not the contents of the inherited template.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
template = info_association.template
@@ -939,7 +940,8 @@ class LibraryFolder( object ):
# See if we have any associated templates. The get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
if inherited:
@@ -948,7 +950,12 @@ class LibraryFolder( object ):
template = info_association.template
# See if we have any field contents, but only if the info_association was
# not inherited ( we do not want to display the inherited contents ).
- if not inherited and get_contents:
+ # (gvk: 8/30/10) Based on conversations with Dan, we agreed to ALWAYS
inherit
+ # contents. We'll use this behavior until we hear from the community
that
+ # contents should not be inherited. If we don't hear anything for a
while,
+ # eliminate the old commented out behavior.
+ #if not inherited and get_contents:
+ if get_contents:
info = info_association.info
if info:
return template.get_widgets( trans.user, info.content )
@@ -1160,7 +1167,8 @@ class LibraryDatasetDatasetAssociation(
# See if we have any associated templatesThe get_contents
# param is passed by callers that are inheriting a template - these
# are usually new library datsets for which we want to include template
- # fields on the upload form.
+ # fields on the upload form, but not necessarily the contents of the
+ # inherited template saved for the parent.
info_association, inherited = self.get_info_association()
if info_association:
if inherited:
@@ -1169,7 +1177,12 @@ class LibraryDatasetDatasetAssociation(
template = info_association.template
# See if we have any field contents, but only if the info_association was
# not inherited ( we do not want to display the inherited contents ).
- if not inherited and get_contents:
+ # (gvk: 8/30/10) Based on conversations with Dan, we agreed to ALWAYS
inherit
+ # contents. We'll use this behavior until we hear from the community
that
+ # contents should not be inherited. If we don't hear anything for a
while,
+ # eliminate the old commented out behavior.
+ #if not inherited and get_contents:
+ if get_contents:
info = info_association.info
if info:
return template.get_widgets( trans.user, info.content )
--- a/test/functional/test_user_info.py
+++ b/test/functional/test_user_info.py
@@ -126,7 +126,7 @@ class TestUserInfo( TwillTestCase ):
self.check_page_for_string( "Manage User Information" )
self.check_page_for_string( user_info_values[0] )
self.check_page_for_string( user_info_values[1] )
- self.check_page_for_string( '<input type="checkbox"
name="field_2" value="true" checked>' )
+ self.check_page_for_string( '<input type="checkbox"
name="field_2" value="true" checked >' )
def test_015_user_reqistration_single_user_info_forms( self ):
''' Testing user registration with a single user info form
'''
# Logged in as regular_user_11
@@ -155,7 +155,7 @@ class TestUserInfo( TwillTestCase ):
self.check_page_for_string( "Manage User Information" )
self.check_page_for_string( user_info_values[0] )
self.check_page_for_string( user_info_values[1] )
- self.check_page_for_string( '<input type="checkbox"
name="field_2" value="true" checked>' )
+ self.check_page_for_string( '<input type="checkbox"
name="field_2" value="true" checked >' )
def test_020_edit_user_info( self ):
"""Testing editing user info as a regular user"""
# Logged in as regular_user_12
@@ -179,32 +179,23 @@ class TestUserInfo( TwillTestCase ):
# Test editing the user info
self.edit_user_info( ['Research', 'PSU'] )
def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to
pass"""
# Logged in as regular_user_12
self.logout()
self.login( email=admin_user.email )
+ ##################
+ # Mark all forms deleted
+ ##################
+ for form_name in [ form_one_name ]:
+ form = get_form( form_name )
+ mark_form_deleted( form )
###############
- # Mark form_one as deleted ( form_two was marked deleted earlier )
+ # Purge appropriate users
###############
- form_latest = get_form( form_one_name )
- mark_form_deleted( form_latest )
- ###############
- # Manually delete the test_user11
- ###############
- self.mark_user_deleted( user_id=self.security.encode_id( regular_user11.id ),
email=regular_user11.email )
- refresh( regular_user11 )
- self.purge_user( self.security.encode_id( regular_user11.id ),
regular_user11.email )
- refresh( regular_user11 )
- # We should now only the the user and his private role
- delete_user_roles( regular_user11 )
- delete_obj( regular_user11 )
- ###############
- # Manually delete the test_user12
- ###############
- refresh( regular_user12 )
- self.mark_user_deleted( user_id=self.security.encode_id( regular_user12.id ),
email=regular_user12.email )
- refresh( regular_user12 )
- self.purge_user( self.security.encode_id( regular_user12.id ),
regular_user12.email )
- refresh( regular_user12 )
- # We should now only the the user and his private role
- delete_user_roles( regular_user12 )
- delete_obj( regular_user12 )
+ for user in [ regular_user11, regular_user12 ]:
+ self.mark_user_deleted( user_id=self.security.encode_id( user.id ),
email=user.email )
+ refresh( user )
+ self.purge_user( self.security.encode_id( user.id ), user.email )
+ refresh( user )
+ delete_user_roles( user )
+ delete_obj( user )
--- a/templates/library/common/select_template.mako
+++ b/templates/library/common/select_template.mako
@@ -66,13 +66,18 @@
<input type="submit" name="add_template_button"
value="Add template to ${item_desc}"/></div></form>
- %if template_select_list.get_selected() != ('Select one',
'none'):
- <div style="clear: both"></div>
+ </div>
+</div>
+<p/>
+%if template_select_list.get_selected() != ('Select one', 'none'):
+ <div class="toolForm">
+ <div class="toolFormTitle">Layout of selected
template</div>
+ <div class="toolFormBody"><div class="form-row">
%for i, field in enumerate( widgets ):
<div class="form-row"><label>${field[
'label' ]}</label>
- ${field[ 'widget' ].get_html()}
+ ${field[ 'widget' ].get_html( disabled=True )}
<div class="toolParamHelp" style="clear:
both;">
${field[ 'helptext' ]}
</div>
@@ -80,6 +85,6 @@
</div>
%endfor
</div>
- %endif
+ </div></div>
-</div>
+%endif
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1406,6 +1406,45 @@ class TwillTestCase( unittest.TestCase )
self.check_page_for_string( desc )
self.check_page_for_string( formtype )
self.home()
+ # Form stuff
+ def create_single_field_type_form_definition( self, name, desc, formtype, field_type
):
+ """
+ Create a new form definition containing 1 field of a specified type (
AddressField, CheckboxField, SelectField,
+ TextArea, TextField, WorkflowField ). The form_type param value should not be
'Sequencing Sample Form,' use
+ create_form() above for that.
+ """
+ self.home()
+ # Create a new form definition
+ self.visit_url( "%s/forms/new" % self.url )
+ self.check_page_for_string( 'Create a new form definition' )
+ tc.fv( "1", "name", name )
+ tc.fv( "1", "description", desc )
+ tc.fv( "1", "form_type_selectbox", formtype )
+ tc.submit( "create_form_button" )
+ # Add 1 AddressField to the new form definition
+ field_name = 'field_name_0'
+ field_contents = field_type
+ field_help_name = 'field_helptext_0'
+ field_help_contents = '%s help' % field_type
+ field_default = 'field_default_0'
+ field_default_contents = '%s default contents' % field_type
+ tc.fv( "1", field_name, field_contents )
+ tc.fv( "1", field_help_name, field_help_contents )
+ self.refresh_form( 'field_type_0', field_type )
+ if field_type == 'SelectField':
+ # Add 2 options so our select list is functional
+ tc.submit( "addoption_0" )
+ tc.fv( "1", "field_0_option_0", "One" )
+ tc.submit( "addoption_0" )
+ tc.fv( "1", "field_0_option_1", "Two" )
+ tc.fv( "1", field_default, field_default_contents )
+ tc.submit( "save_changes_button" )
+ self.home()
+ self.visit_url( "%s/forms/manage" % self.url )
+ self.check_page_for_string( name )
+ self.check_page_for_string( desc )
+ self.check_page_for_string( formtype )
+ self.home()
def edit_form( self, form_current_id, form_name, new_form_name="Form One's
Name (Renamed)", new_form_desc="This is Form One's description
(Re-described)"):
"""
Edit form details; name & description
@@ -1459,6 +1498,15 @@ class TwillTestCase( unittest.TestCase )
check_str = "The form '%s' has been updated with the changes."
% form_name
self.check_page_for_string( check_str )
self.home()
+ def mark_form_deleted( self, form_id ):
+ """Mark a form_definition as deleted"""
+ self.home()
+ url = "%s/forms/manage?operation=delete&id=%s" % ( self.url,
form_id )
+ self.visit_url( url )
+ check_str = "1 form(s) is deleted."
+ self.check_page_for_string( check_str )
+ self.home()
+
# Requests stuff
def check_request_grid(self, state, request_name, deleted=False):
self.home()
@@ -1603,7 +1651,11 @@ class TwillTestCase( unittest.TestCase )
# Library stuff
def add_library_template( self, cntrller, item_type, library_id, form_id, form_name,
folder_id=None, ldda_id=None ):
- """Add a new info template to a library item"""
+ """
+ Add a new info template to a library item - the template will ALWAYS BE SET TO
INHERITABLE here. If you want to
+ dis-inherit your template, call the manage_library_template_inheritance() below
immediately after you call this
+ method in your test code.
+ """
self.home()
if item_type == 'library':
url =
"%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s"
% \
@@ -1616,11 +1668,31 @@ class TwillTestCase( unittest.TestCase )
( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
self.visit_url( url )
self.check_page_for_string ( "Select a template for the" )
- tc.fv( '1', 'form_id', form_id )
- tc.fv( '1', 'inherit', '1' )
- tc.submit( 'add_template_button' )
+ self.refresh_form( "form_id", form_id )
+ # For some unknown reason, twill barfs if the form number ( 1 ) is used in the
following
+ # rather than the form anme ( select_template ), so we have to use the form
name.
+ tc.fv( "select_template", "inheritable", '1' )
+ tc.submit( "add_template_button" )
self.check_page_for_string = 'A template based on the form "%s" has
been added to this' % form_name
self.home()
+ def manage_library_template_inheritance( self, cntrller, item_type, library_id,
folder_id=None, ldda_id=None, inheritable=True ):
+ # If inheritable is True, the item is currently inheritable.
+ self.home()
+ if item_type == 'library':
+ url =
"%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s"
% \
+ ( self.url, cntrller, item_type, library_id )
+ elif item_type == 'folder':
+ url =
"%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s"
% \
+ ( self.url, cntrller, item_type, library_id, folder_id )
+ elif item_type == 'ldda':
+ url =
"%s/library_common/manage_template_inheritance?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s&ldda_id=%s"
% \
+ ( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
+ self.visit_url( url )
+ if inheritable:
+ self.check_page_for_string = 'will no longer be inherited to contained
folders and datasets'
+ else:
+ self.check_page_for_string = 'will now be inherited to contained folders
and datasets'
+ self.home()
def browse_libraries_admin( self, deleted=False, check_str1='',
check_str2='', not_displayed1='' ):
self.visit_url(
'%s/library_admin/browse_libraries?sort=name&f-description=All&f-name=All&f-deleted=%s'
% ( self.url, str( deleted ) ) )
if check_str1:
@@ -1718,13 +1790,14 @@ class TwillTestCase( unittest.TestCase )
self.home()
# Library folder stuff
- def add_folder( self, controller, library_id, folder_id, name='Folder One',
description='This is Folder One' ):
+ def add_folder( self, cntrller, library_id, folder_id, name='Folder One',
description='This is Folder One' ):
"""Create a new folder"""
self.home()
- self.visit_url(
"%s/library_common/create_folder?cntrller=%s&library_id=%s&parent_id=%s"
% ( self.url, controller, library_id, folder_id ) )
+ url =
"%s/library_common/create_folder?cntrller=%s&library_id=%s&parent_id=%s"
% ( self.url, cntrller, library_id, folder_id )
+ self.visit_url( url )
self.check_page_for_string( 'Create a new folder' )
- tc.fv( "1", "name", name ) # form field 1 is the field named
name...
- tc.fv( "1", "description", description ) # form field 2 is
the field named description...
+ tc.fv( "1", "name", name )
+ tc.fv( "1", "description", description )
tc.submit( "new_folder_button" )
check_str = "The new folder named '%s' has been added to the data
library." % name
self.check_page_for_string( check_str )
@@ -1765,14 +1838,32 @@ class TwillTestCase( unittest.TestCase )
# Library dataset stuff
def add_library_dataset( self, cntrller, filename, library_id, folder_id,
folder_name,
file_type='auto', dbkey='hg18', roles=[],
message='', root=False,
- template_field_name1='',
template_field_contents1='', show_deleted='False',
- upload_option='upload_file' ):
+ template_field_name1='',
template_field_contents1='',
+ template_refresh_field_name='',
template_refresh_field_contents='',
+ field_0_short_desc='', field_0_name='',
field_0_institution='',
+ field_0_address='', field_0_city='',
field_0_state='', field_0_postal_code='',
+ field_0_country='', show_deleted='False',
upload_option='upload_file' ):
"""Add a dataset to a folder"""
filename = self.get_filename( filename )
self.home()
self.visit_url(
"%s/library_common/upload_library_dataset?cntrller=%s&library_id=%s&folder_id=%s&upload_option=%s&message=%s"
% \
( self.url, cntrller, library_id, folder_id, upload_option,
message.replace( ' ', '+' ) ) )
self.check_page_for_string( 'Upload files' )
+ # A template containing an AddressField may be displayed on the upload form.
+ # If this is the case, we need to refresh the form with the passeed
tmplate_field_name1.
+ if template_refresh_field_name and template_refresh_field_contents:
+ self.refresh_form( template_refresh_field_name,
template_refresh_field_contents )
+ tc.fv( "1", "field_0_short_desc", field_0_short_desc )
+ tc.fv( "1", "field_0_name", field_0_name )
+ tc.fv( "1", "field_0_institution", field_0_institution )
+ tc.fv( "1", "field_0_address", field_0_address )
+ tc.fv( "1", "field_0_city", field_0_city )
+ tc.fv( "1", "field_0_state", field_0_state )
+ tc.fv( "1", "field_0_postal_code", field_0_postal_code )
+ tc.fv( "1", "field_0_country", field_0_country )
+ # Add template field contents, if any...
+ if template_field_name1:
+ tc.fv( "1", template_field_name1, template_field_contents1 )
tc.fv( "1", "library_id", library_id )
tc.fv( "1", "folder_id", folder_id )
tc.fv( "1", "show_deleted", show_deleted )
@@ -1782,9 +1873,6 @@ class TwillTestCase( unittest.TestCase )
tc.fv( "1", "message", message.replace( '+', '
' ) )
for role_id in roles:
tc.fv( "1", "roles", role_id )
- # Add template field contents, if any...
- if template_field_name1:
- tc.fv( "1", template_field_name1, template_field_contents1 )
tc.submit( "runtool_btn" )
if root:
check_str = "Added 1 datasets to the library '%s' (each is
selected)." % folder_name
--- a/templates/library/common/common.mako
+++ b/templates/library/common/common.mako
@@ -22,7 +22,7 @@
has_contents = True
label = field[ 'label' ]
value = 'checked'
- elif isinstance( field[ 'widget' ], WorkflowField ) and field[
'widget' ].value not in [ 'none', 'None', None ]:
+ elif isinstance( field[ 'widget' ], WorkflowField ) and str( field[
'widget' ].value ).lower() not in [ 'none' ]:
has_contents = True
label = field[ 'label' ]
widget = field[ 'widget' ]
@@ -35,7 +35,7 @@
else:
# If we didn't find the selected workflow option above, we'll
just print the value
value = field[ 'widget' ].value
- elif isinstance( field[ 'widget' ], AddressField ) and field[
'widget' ].value not in [ 'none', 'None', None ]:
+ elif isinstance( field[ 'widget' ], AddressField ) and str( field[
'widget' ].value ).lower() not in [ 'none' ]:
has_contents = True
widget = field[ 'widget' ]
address = trans.sa_session.query( trans.model.UserAddress ).get( int(
widget.value ) )
@@ -69,71 +69,77 @@
else:
can_modify = False
%>
- %if widgets:
- %if editable and can_modify:
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">
- %if inherited:
- Other information <i>- this is an inherited template and is
not required to be used with this ${item_type}</i>
- %else:
- Other information
- %endif
- %if info_association and not inherited and can_modify:
+ %if editable and can_modify:
+ <p/>
+ <div class="toolForm">
+ <div class="toolFormTitle">Other information
+ <a id="item-${item.id}-popup" class="popup-arrow"
style="display: none;">▼</a>
+ <div popupmenu="item-${item.id}-popup">
+ %if info_association and inherited and can_modify:
## "inherited" will be true only if the
info_association is not associated with the current item,
- ## in which case we do not want to render the following popup
menu.
- <a id="item-${item.id}-popup"
class="popup-arrow" style="display: none;">▼</a>
- <div popupmenu="item-${item.id}-popup">
- <a class="action-button" href="${h.url_for(
controller='library_common', action='edit_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}">Edit template</a>
- <a class="action-button" href="${h.url_for(
controller='library_common', action='delete_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}">Delete template</a>
- %if item_type not in [ 'ldda',
'library_dataset' ]:
- %if info_association.inheritable:
- <a class="action-button"
href="${h.url_for( controller='library_common',
action='manage_template_inheritance', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}">Dis-inherit template</a>
- %else:
- <a class="action-button"
href="${h.url_for( controller='library_common',
action='manage_template_inheritance', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}">Inherit template</a>
- %endif
+ ## which means that the currently display template has not yet
been saved for the current item.
+ <a class="action-button" href="${h.url_for(
controller='library_common', action='add_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}">Select a different template</a>
+ %elif info_association and not inherited and can_modify:
+ <a class="action-button" href="${h.url_for(
controller='library_common', action='edit_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}">Edit template</a>
+ <a class="action-button" href="${h.url_for(
controller='library_common', action='delete_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}">Delete template</a>
+ %if item_type not in [ 'ldda', 'library_dataset'
]:
+ %if info_association.inheritable:
+ <a class="action-button"
href="${h.url_for( controller='library_common',
action='manage_template_inheritance', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}">Dis-inherit template</a>
+ %else:
+ <a class="action-button"
href="${h.url_for( controller='library_common',
action='manage_template_inheritance', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}">Inherit template</a>
%endif
- </div>
+ %endif
%endif
</div>
- <div class="toolFormBody">
- <form name="edit_info" id="edit_info"
action="${h.url_for( controller='library_common',
action='edit_template_info', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}" method="post">
- %for i, field in enumerate( widgets ):
- <div class="form-row">
- <label>${field[ 'label' ]}</label>
- ${field[ 'widget' ].get_html()}
- <div class="toolParamHelp"
style="clear: both;">
- ${field[ 'helptext' ]}
- </div>
- <div style="clear: both"></div>
+ </div>
+ <div class="toolFormBody">
+ %if inherited:
+ <div class="form-row">
+ <font color="red">
+ <b>
+ This is an inherited template and is not required to be
used with this ${item_type}. You can
+ <a href="${h.url_for(
controller='library_common', action='add_template', cntrller=cntrller,
item_type=item_type, library_id=library_id, folder_id=folder_id, ldda_id=ldda_id,
show_deleted=show_deleted )}"><font color="red">select a different
template</font></a>
+ or fill in the desired fields and save this one. This
template will not be assocaiated with this ${item_type} until you click the Save button.
+ </b>
+ </font>
+ </div>
+ %endif
+ <form name="edit_info" id="edit_info"
action="${h.url_for( controller='library_common',
action='edit_template_info', cntrller=cntrller, item_type=item_type,
library_id=library_id, folder_id=folder_id, ldda_id=ldda_id, show_deleted=show_deleted
)}" method="post">
+ %for i, field in enumerate( widgets ):
+ <div class="form-row">
+ <label>${field[ 'label' ]}</label>
+ ${field[ 'widget' ].get_html()}
+ <div class="toolParamHelp" style="clear:
both;">
+ ${field[ 'helptext' ]}
</div>
- %endfor
- <div class="form-row">
- <input type="submit"
name="edit_info_button" value="Save"/>
+ <div style="clear:
both"></div></div>
- </form>
- </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit"
name="edit_info_button" value="Save"/>
+ </div>
+ </form></div>
- <p/>
- %elif widget_fields_have_contents:
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">Other information about
${item.name}</div>
- <div class="toolFormBody">
- %for i, field in enumerate( widgets ):
- ${render_template_field( field )}
- %endfor
- </div>
+ </div>
+ <p/>
+ %elif widget_fields_have_contents:
+ <p/>
+ <div class="toolForm">
+ <div class="toolFormTitle">Other information about
${item.name}</div>
+ <div class="toolFormBody">
+ %for i, field in enumerate( widgets ):
+ ${render_template_field( field )}
+ %endfor
</div>
- <p/>
- %endif
+ </div>
+ <p/>
%endif
</%def><%def name="render_upload_form( cntrller, upload_option, action,
library_id, folder_id, replace_dataset, file_formats, dbkeys, widgets, roles, history,
show_deleted )"><% import os, os.path %>
%if upload_option in [ 'upload_file', 'upload_directory',
'upload_paths' ]:
- <div class="toolForm" id="upload_library_dataset">
+ <div class="toolForm"
id="upload_library_dataset_tool_form">
%if upload_option == 'upload_directory':
<div class="toolFormTitle">Upload a directory of
files</div>
%elif upload_option == 'upload_paths':
@@ -142,7 +148,7 @@
<div class="toolFormTitle">Upload files</div>
%endif
<div class="toolFormBody">
- <form name="upload_library_dataset"
action="${action}" enctype="multipart/form-data"
method="post">
+ <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}"/>
--- a/lib/galaxy/web/controllers/library_common.py
+++ b/lib/galaxy/web/controllers/library_common.py
@@ -7,6 +7,7 @@ from galaxy.util.json import to_json_str
from galaxy.tools.actions import upload_common
from galaxy.model.orm import *
from galaxy.util.streamball import StreamBall
+from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea,
TextField, WorkflowField
import logging, tempfile, zipfile, tarfile, os, sys
if sys.version_info[:2] < ( 2, 6 ):
@@ -943,7 +944,7 @@ class LibraryCommon( BaseController, Use
# Check to see if the user selected roles to associate with the
DATASET_ACCESS permission
# on the dataset that would cause accessibility issues.
roles = params.get( 'roles', False )
- error = None
+ error = False
if upload_option == 'upload_paths' and not
trans.app.config.allow_library_path_paste:
error = True
message = '"allow_library_path_paste" is not defined in the
Galaxy configuration file'
@@ -966,11 +967,41 @@ class LibraryCommon( BaseController, Use
status='error' ) )
else:
- # See if we have any inherited templates, but do not inherit contents.
+ # See if we have any inherited templates.
info_association, inherited = folder.get_info_association( inherited=True
)
if info_association and info_association.inheritable:
template_id = str( info_association.template.id )
- widgets = folder.get_template_widgets( trans, get_contents=False )
+ widgets = folder.get_template_widgets( trans, get_contents=True )
+ processed_widgets = []
+ # The list of widgets may include an AddressField which we need to
save if it is new
+ for index, widget_dict in enumerate( widgets ):
+ widget = widget_dict[ 'widget' ]
+ if isinstance( widget, AddressField ):
+ value = util.restore_text( params.get( 'field_%i' %
index, '' ) )
+ if value == 'new':
+ if self.field_param_values_ok( index,
'AddressField', **kwd ):
+ # Save the new address
+ address = trans.app.model.UserAddress(
user=trans.user )
+ self.save_widget_field( trans, address, index, **kwd
)
+ widget.value = str( address.id )
+ widget_dict[ 'widget' ] = widget
+ processed_widgets.append( widget_dict )
+ # FIXME: ( hack ) It is now critical to update the
value of 'field_%i', replacing the string
+ # 'new' with the new address id. This is
necessary because the upload_dataset()
+ # method below calls the handle_library_params()
method, which does not parse the
+ # widget fields, it instead pulls form values from
kwd. See the FIXME comments in the
+ # handle_library_params() method...
+ kwd[ 'field_%i' % index ] = str( address.id
)
+ else:
+ # The invalid address won't be saved, but we
cannot dispaly error
+ # messages on the upload form due to the ajax upload
already occurring.
+ # When we re-engineer the upload process ( currently
under way ), we
+ # will be able to check the form values before the
ajax upload occurs
+ # in the background. For now, we'll do
nothing...
+ pass
+ else:
+ processed_widgets.append( widget_dict )
+ widgets = processed_widgets
else:
template_id = 'None'
widgets = []
@@ -1039,10 +1070,34 @@ class LibraryCommon( BaseController, Use
show_deleted=show_deleted,
message=util.sanitize_text(
message ),
status=status ) )
- # See if we have any inherited templates, but do not inherit contents.
+ # Note: if the upload form was submitted due to refresh_on_demand 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
+ # attribute of the html input file type field is typically ignored by browsers as
a security precaution.
+
+ # See if we have any inherited templates.
info_association, inherited = folder.get_info_association( inherited=True )
if info_association and info_association.inheritable:
- widgets = folder.get_template_widgets( trans, get_contents=False )
+ widgets = folder.get_template_widgets( trans, get_contents=True )
+ # Handle form submission via refresh_on_change by keeping the contents of
widget fields
+ populated_widgets = []
+ for index, widget_dict in enumerate( widgets ):
+ widget = widget_dict[ 'widget' ]
+ if isinstance( widget, AddressField ):
+ value = util.restore_text( params.get( 'field_%i' % index,
'' ) )
+ if value:
+ if value == 'new':
+ # Adding a new address
+ widget.value = value
+ widget_dict[ 'widget' ] = widget
+ elif value == 'none':
+ widget.value = ''
+ widget_dict[ 'widget' ] = widget
+ else:
+ # An existing address object was selected
+ address_obj = trans.sa_session.query(
trans.app.model.UserAddress ).get( int( value ) )
+ widget_dict[ 'widget' ] = address_obj
+ populated_widgets.append( widget_dict )
+ widgets = populated_widgets
else:
widgets = []
upload_option = params.get( 'upload_option', 'upload_file' )
@@ -1132,6 +1187,8 @@ class LibraryCommon( BaseController, Use
message = '"allow_library_path_paste" is not defined in the
Galaxy configuration file'
# Some error handling should be added to this method.
try:
+ # FIXME: instead of passing params here ( chiech have been process 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 )
except:
response_code = 500
@@ -2174,10 +2231,23 @@ class LibraryCommon( BaseController, Use
value = util.restore_text( params.get( 'field_%i' % index,
'' ) )
if value == 'new':
if params.get( 'edit_info_button', False ):
- # Save the new address
- address = trans.app.model.UserAddress( user=trans.user )
- self.save_widget_field( trans, address, index, **kwd )
- widget.value = str( address.id )
+ if self.field_param_values_ok( index, 'AddressField',
**kwd ):
+ # Save the new address
+ address = trans.app.model.UserAddress( user=trans.user )
+ self.save_widget_field( trans, address, index, **kwd )
+ widget.value = str( address.id )
+ else:
+ message = 'Required fields are missing contents.'
+ return trans.response.send_redirect( web.url_for(
controller='library_common',
+
action=action,
+
cntrller=cntrller,
+
use_panels=use_panels,
+
library_id=library_id,
+
folder_id=folder_id,
+ id=id,
+
show_deleted=show_deleted,
+
message=util.sanitize_text( message ),
+
status='error' ) )
else:
# Form was submitted via refresh_on_change
widget.value = 'new'
--- a/templates/library/common/library_dataset_info.mako
+++ b/templates/library/common/library_dataset_info.mako
@@ -90,6 +90,5 @@
%endif
%if widgets:
- ## Templates are not currently supported for library_datasets, only the associated
ldda.
${render_template_fields( cntrller, 'library_dataset', library_id, widgets,
widget_fields_have_contents, info_association=None, inherited=False, editable=False )}
%endif
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -35,6 +35,9 @@ def persist_uploads( params ):
params['files'] = new_files
return params
def handle_library_params( trans, params, folder_id, replace_dataset=None ):
+ # FIXME: the received params has already been parsed by util.Params() by the time it
reaches here,
+ # so no complex objects remain. This is not good because it does not allow for those
objects to be
+ # manipulated here. The receivd params should be the original kwd from the initial
request.
library_bunch = util.bunch.Bunch()
library_bunch.replace_dataset = replace_dataset
library_bunch.message = params.get( 'message', '' )
@@ -42,9 +45,8 @@ def handle_library_params( trans, params
library_bunch.template_field_contents = []
template_id = params.get( 'template_id', None )
library_bunch.folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get(
trans.security.decode_id( folder_id ) )
- # We are inheriting the folder's info_association, so we did not
- # receive any inherited contents, but we may have redirected here
- # after the user entered template contents ( due to errors ).
+ # We are inheriting the folder's info_association, so we may have received
inherited contents or we may have redirected
+ # here after the user entered template contents ( due to errors ).
if template_id not in [ None, 'None' ]:
library_bunch.template = trans.sa_session.query( trans.app.model.FormDefinition
).get( template_id )
for field_index in range( len( library_bunch.template.fields ) ):
--- a/lib/galaxy/web/controllers/tool_runner.py
+++ b/lib/galaxy/web/controllers/tool_runner.py
@@ -179,6 +179,8 @@ class ToolRunner( BaseController ):
replace_dataset = trans.sa_session.query(
trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) )
else:
replace_dataset = None
+ # FIXME: instead of passing params here ( chiech have been process 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,
nonfile_params, nonfile_params.folder_id, replace_dataset )
else:
library_bunch = None