galaxy-commits
Threads by month
- ----- 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
galaxy-dist commit 2e2ee0289d67: Fix BLAST+ regression from changeset 535d276c92bc (loc file columns)
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User peterjc <p.j.a.cock(a)googlemail.com>
# Date 1289925107 0
# Node ID 2e2ee0289d67d244954aa05bfe315dbb5ff413eb
# Parent d2d0c199c20ddf942e1e2587dc9aede8acd9cebc
Fix BLAST+ regression from changeset 535d276c92bc (loc file columns)
--- a/tools/ncbi_blast_plus/ncbi_blastn_wrapper.xml
+++ b/tools/ncbi_blast_plus/ncbi_blastn_wrapper.xml
@@ -40,10 +40,13 @@ blastn
</param><when value="db"><param name="database" type="select" label="Nucleotide BLAST database">
- <!-- <options from_data_table="blastdb" /> -->
+ <!-- The BLAST loc file has three columns:
+ column 0 is an identifier (not used here, see legacy megablast wrapper),
+ column 1 is the caption (show this to the user),
+ column 2 is the database path (given to BLAST+) --><options from_file="blastdb.loc">
- <column name="name" index="2"/>
- <column name="value" index="0"/>
+ <column name="name" index="1"/>
+ <column name="value" index="2"/></options></param><param name="subject" type="hidden" value="" />
--- a/tools/ncbi_blast_plus/ncbi_blastp_wrapper.xml
+++ b/tools/ncbi_blast_plus/ncbi_blastp_wrapper.xml
@@ -41,10 +41,13 @@ blastp
</param><when value="db"><param name="database" type="select" label="Protein BLAST database">
- <!-- <options from_data_table="blastdb_p" /> -->
+ <!-- The BLAST loc file has three columns:
+ column 0 is an identifier (not used),
+ column 1 is the caption (show this to the user),
+ column 2 is the database path (given to BLAST+) --><options from_file="blastdb_p.loc">
- <column name="name" index="2"/>
- <column name="value" index="0"/>
+ <column name="name" index="1"/>
+ <column name="value" index="2"/></options></param><param name="subject" type="hidden" value="" />
--- a/tools/ncbi_blast_plus/ncbi_tblastx_wrapper.xml
+++ b/tools/ncbi_blast_plus/ncbi_tblastx_wrapper.xml
@@ -39,10 +39,13 @@ tblastx
</param><when value="db"><param name="database" type="select" label="Nucleotide BLAST database">
- <!-- <options from_data_table="blastdb" /> -->
+ <!-- The BLAST loc file has three columns:
+ column 0 is an identifier (not used here, see legacy megablast wrapper),
+ column 1 is the caption (show this to the user),
+ column 2 is the database path (given to BLAST+) --><options from_file="blastdb.loc">
- <column name="name" index="2"/>
- <column name="value" index="0"/>
+ <column name="name" index="1"/>
+ <column name="value" index="2"/></options></param><param name="subject" type="hidden" value="" />
--- a/tools/ncbi_blast_plus/ncbi_blastx_wrapper.xml
+++ b/tools/ncbi_blast_plus/ncbi_blastx_wrapper.xml
@@ -40,10 +40,13 @@ blastx
</param><when value="db"><param name="database" type="select" label="Protein BLAST database">
- <!-- <options from_data_table="blastdb_p" /> -->
+ <!-- The BLAST loc file has three columns:
+ column 0 is an identifier (not used),
+ column 1 is the caption (show this to the user),
+ column 2 is the database path (given to BLAST+) --><options from_file="blastdb_p.loc">
- <column name="name" index="2"/>
- <column name="value" index="0"/>
+ <column name="name" index="1"/>
+ <column name="value" index="2"/></options></param><param name="subject" type="hidden" value="" />
--- a/tools/ncbi_blast_plus/ncbi_tblastn_wrapper.xml
+++ b/tools/ncbi_blast_plus/ncbi_tblastn_wrapper.xml
@@ -40,10 +40,13 @@ tblastn
</param><when value="db"><param name="database" type="select" label="Nucleotide BLAST database">
- <!-- <options from_data_table="blastdb" /> -->
+ <!-- The BLAST loc file has three columns:
+ column 0 is an identifier (not used here, see legacy megablast wrapper),
+ column 1 is the caption (show this to the user),
+ column 2 is the database path (given to BLAST+) --><options from_file="blastdb.loc">
- <column name="name" index="2"/>
- <column name="value" index="0"/>
+ <column name="name" index="1"/>
+ <column name="value" index="2"/></options></param><param name="subject" type="hidden" value="" />
1
0
galaxy-dist commit 1bf064c8ab88: Fixed functional tests and samples grid alignment bug
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1289928056 18000
# Node ID 1bf064c8ab88621dd58890f6cd56ad4900d10d6b
# Parent 2e2ee0289d67d244954aa05bfe315dbb5ff413eb
Fixed functional tests and samples grid alignment bug
--- a/test/functional/test_sample_tracking.py
+++ b/test/functional/test_sample_tracking.py
@@ -341,7 +341,7 @@ class TestFormsAndRequests( TwillTestCas
request_id=self.security.encode_id( request1.id ),
strings_displayed=[ 'History of sequencing request "%s"' % request1.name,
request1.states.NEW,
- 'Request created' ],
+ 'Sequencing request created' ],
strings_not_displayed=[ request1.states.SUBMITTED,
request1.states.COMPLETE,
request1.states.REJECTED ] )
@@ -412,7 +412,7 @@ class TestFormsAndRequests( TwillTestCas
self.add_samples( cntrller='requests',
request_id=self.security.encode_id( request1.id ),
sample_value_tuples=sample_value_tuples,
- strings_displayed=[ 'Add Samples to Request "%s"' % request1.name,
+ strings_displayed=[ 'Add Samples to Sequencing Request "%s"' % request1.name,
'<input type="text" name="sample_0_name" value="Sample_1" size="10"/>' ], # sample name input field
strings_displayed_after_submit=strings_displayed_after_submit )
# check the new sample field values on the request page
@@ -446,7 +446,7 @@ class TestFormsAndRequests( TwillTestCas
self.edit_samples( cntrller='requests',
request_id=self.security.encode_id( request1.id ),
sample_value_tuples=new_sample_value_tuples,
- strings_displayed=[ 'Edit Current Samples of Request "%s"' % request1.name,
+ strings_displayed=[ 'Edit Current Samples of Sequencing Request "%s"' % request1.name,
'<input type="text" name="sample_0_name" value="Sample1" size="10"/>' ], # sample name input field
strings_displayed_after_submit=strings_displayed_after_submit )
# check the changed sample field values on the request page
@@ -465,14 +465,14 @@ class TestFormsAndRequests( TwillTestCas
self.submit_request( cntrller='requests',
request_id=self.security.encode_id( request1.id ),
request_name=request1.name,
- strings_displayed_after_submit=[ 'The request has been submitted.' ] )
+ strings_displayed_after_submit=[ 'The sequencing request has been submitted.' ] )
refresh( request1 )
# Make sure the request is showing in the 'submitted' filter
self.check_request_grid( cntrller='requests',
state=request1.states.SUBMITTED,
strings_displayed=[ request1.name ] )
# Make sure the request's state is now set to 'submitted'
- assert request1.state is not request1.states.SUBMITTED, "The state of the request '%s' should be set to '%s'" \
+ assert request1.state is not request1.states.SUBMITTED, "The state of the sequencing request '%s' should be set to '%s'" \
% ( request1.name, request1.states.SUBMITTED )
# the sample state should appear once for each sample
strings_displayed_count = [ ( request1.type.states[0].name, len( request1.samples ) ) ]
@@ -485,8 +485,8 @@ class TestFormsAndRequests( TwillTestCas
strings_displayed_count=strings_displayed_count,
strings_not_displayed=strings_not_displayed )
strings_displayed=[ 'History of sequencing request "%s"' % request1.name,
- 'Request submitted by %s' % regular_user1.email,
- 'Request created' ]
+ 'Sequencing request submitted by %s' % regular_user1.email,
+ 'Sequencing request created' ]
strings_displayed_count = [ ( request1.states.SUBMITTED, 1 ) ]
self.view_request_history( cntrller='requests',
request_id=self.security.encode_id( request1.id ),
@@ -519,7 +519,7 @@ class TestFormsAndRequests( TwillTestCas
self.add_bar_codes( cntrller='requests_admin',
request_id=self.security.encode_id( request1.id ),
bar_codes=bar_codes,
- strings_displayed=[ 'Edit Current Samples of Request "%s"' % request1.name ],
+ strings_displayed=[ 'Edit Current Samples of Sequencing Request "%s"' % request1.name ],
strings_displayed_after_submit=strings_displayed_after_submit )
# the second sample state should appear once for each sample
strings_displayed_count = [ ( request1.type.states[1].name, len( request1.samples ) ),
@@ -538,7 +538,7 @@ class TestFormsAndRequests( TwillTestCas
# check history of each sample
for sample in request1.samples:
strings_displayed = [ 'Events for Sample "%s"' % sample.name,
- 'Request submitted and sample state set to %s' % request1.type.states[0].name,
+ 'Sequencing request submitted and sample state set to %s' % request1.type.states[0].name,
request1.type.states[0].name,
request1.type.states[1].name ]
self.view_sample_history( cntrller='requests_admin',
@@ -558,9 +558,9 @@ class TestFormsAndRequests( TwillTestCas
if index > 1:
# status message
if index == len( request_type1.states ) - 1:
- status_msg = 'All samples of this request are in the final sample state (%s).' % state.name
+ status_msg = 'All samples of this sequencing request are in the final sample state (%s).' % state.name
else:
- status_msg = 'All samples of this request are in the (%s) sample state. ' % state.name
+ status_msg = 'All samples of this sequencing request are in the (%s) sample state. ' % state.name
# check email notification message
email_msg = ''
if state.id in [ email_state.id for email_state in email_notification_sample_states ]:
@@ -568,7 +568,7 @@ class TestFormsAndRequests( TwillTestCas
self.change_sample_state( request_id=self.security.encode_id( request1.id ),
sample_ids=[ sample.id for sample in request1.samples ],
new_sample_state_id=self.security.encode_id( state.id ),
- strings_displayed=[ 'Edit Current Samples of Request "%s"' % request1.name ],
+ strings_displayed=[ 'Edit Current Samples of Sequencing Request "%s"' % request1.name ],
strings_displayed_after_submit = [ status_msg, email_msg ] )
# check request history page
if index == len( request_type1.states ) - 1:
@@ -584,7 +584,7 @@ class TestFormsAndRequests( TwillTestCas
self.check_request_grid( cntrller='requests_admin',
state='Complete',
strings_displayed=[ request1.name ] )
- assert request1.state is not request1.states.COMPLETE, "The state of the request '%s' should be set to '%s'" \
+ assert request1.state is not request1.states.COMPLETE, "The state of the sequencing request '%s' should be set to '%s'" \
% ( request1.name, request1.states.COMPLETE )
# def test_045_admin_create_request_on_behalf_of_regular_user( self ):
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -113,27 +113,23 @@
</script></%def>
-<%def name="render_editable_sample_row( cntrller, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )">
+<%def name="render_editable_sample_row( cntrller, request, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )"><%
+ trans.sa_session.refresh( request )
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_rejected = request.is_rejected
+ is_complete = request.is_complete
+ is_submitted = request.is_submitted
+ is_unsubmitted = request.is_unsubmitted
if sample:
- trans.sa_session.refresh( sample.request )
- is_complete = sample.request.is_complete
- is_rejected = request.is_rejected
- is_submitted = sample.request.is_submitted
- is_unsubmitted = sample.request.is_unsubmitted
can_delete_samples = editing_samples and request.samples and ( ( is_admin and not is_complete ) or is_unsubmitted )
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
- display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
display_datasets = request.samples and ( is_complete or is_submitted )
else:
- is_complete = False
- is_submitted = False
- is_unsubmitted = False
can_delete_samples = False
display_checkboxes = False
- display_bar_code = False
display_datasets = False
+ display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
%><%
if display_checkboxes and trans.security.encode_id( sample.id ) in encoded_selected_sample_ids:
@@ -152,15 +148,13 @@
</td>
%if display_bar_code:
<td valign="top">
- %if is_admin:
+ %if is_admin and is_submitted:
<input type="text" name="sample_${sample_widget_index}_bar_code" value="${sample_widget['bar_code']}" size="10"/>
%else:
${sample_widget['bar_code']}
<input type="hidden" name="sample_${sample_widget_index}_bar_code" value="${sample_widget['bar_code']}"/>
%endif
</td>
- %else:
- <td></td>
%endif
%if sample:
%if is_unsubmitted:
@@ -305,7 +299,7 @@
sample = None
%>
%if editing_samples:
- <tr>${render_editable_sample_row( cntrller, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, request, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
%elif sample:
<tr><td>
@@ -401,7 +395,7 @@
</tr>
%else:
## The Add sample button was clicked for this sample_widget
- <tr>${render_editable_sample_row( cntrller, None, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, request, None, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
%endif
%endfor
</tbody>
1
0
galaxy-dist commit 7bded9108bd8: More miscellaneous Sample Tracking cleanup and bug fixes, move supported form_builder field types from form_builder.BaseField to Request.model and Sample.model.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# 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 1290007512 18000
# Node ID 7bded9108bd8297ea609e9ec06bbe516b5f0b83a
# Parent a68c74ec8cfbc641db4b6fe424e3f77b9f3c5d3c
More miscellaneous Sample Tracking cleanup and bug fixes, move supported form_builder field types from form_builder.BaseField to Request.model and Sample.model.
--- a/templates/admin/requests/edit_request_type.mako
+++ b/templates/admin/requests/edit_request_type.mako
@@ -28,7 +28,7 @@
</div><div class="form-row"><label>
- Sequencing Request Form definition:
+ Sequencing request form definition:
</label><select name="form_id">
%for form in forms:
@@ -42,7 +42,7 @@
</div><div class="form-row"><label>
- Sample Form definition:
+ Sample form definition:
</label><select name="form_id">
%for form in forms:
--- a/lib/galaxy/web/form_builder.py
+++ b/lib/galaxy/web/form_builder.py
@@ -18,12 +18,6 @@ class BaseField(object):
return ' disabled="disabled"'
else:
return ''
- @staticmethod
- def form_field_types():
- return ['TextField', 'TextArea', 'SelectField', 'CheckboxField', 'AddressField', 'WorkflowField']
- @staticmethod
- def sample_field_types():
- return ['TextField', 'SelectField', 'CheckboxField', 'WorkflowField']
class TextField(BaseField):
"""
@@ -559,8 +553,8 @@ class AddressField(BaseField):
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):
+class WorkflowField( BaseField ):
+ def __init__( self, name, user=None, value=None, params=None ):
self.name = name
self.user = user
self.value = value
@@ -580,7 +574,7 @@ class WorkflowField(BaseField):
else:
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"""
import doctest, sys
@@ -592,11 +586,11 @@ def build_select_field( trans, objs, lab
selected_value='none', refresh_on_change=False, multiple=False, display=None, size=None ):
"""
Build a SelectField given a set of objects. The received params are:
- - objs: the set of object used to populate the option list
+ - objs: the set of objects used to populate the option list
- label_attr: the attribute of each obj (e.g., name, email, etc ) whose value is used to populate each option label. If the string
'self' is passed as label_attr, each obj in objs is assumed to be a string, so the obj itself is used
- select_field_name: the name of the SelectField
- - initial_value: the vlaue of the first option in the SelectField - allows for an option telling the user to select something
+ - initial_value: the value of the first option in the SelectField - allows for an option telling the user to select something
- selected_value: the value of the currently selected option
- refresh_on_change: True if the SelectField should perform a refresh_on_change
"""
--- a/templates/admin/requests/view_request_type.mako
+++ b/templates/admin/requests/view_request_type.mako
@@ -38,7 +38,7 @@
<div style="clear: both"></div></div><div class="form-row">
- <label>Sequencing Request form definition</label>
+ <label>Sequencing request form definition</label>
${request_type.request_form.name}
</div><div class="form-row">
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1495,12 +1495,11 @@ class MetadataFile( object ):
class FormDefinition( object ):
# The following form_builder classes are supported by the FormDefinition class.
- # AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField
supported_field_types = [ AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField ]
types = Bunch( REQUEST = 'Sequencing Request Form',
SAMPLE = 'Sequencing Sample Form',
LIBRARY_INFO_TEMPLATE = 'Library information template',
- USER_INFO = 'User Information' )
+ USER_INFO = 'User Information' )
def __init__( self, name=None, desc=None, fields=[], form_definition_current=None, form_type=None, layout=None ):
self.name = name
self.desc = desc
@@ -1792,6 +1791,8 @@ class RequestTypePermissions( object ):
self.role = role
class Sample( object ):
+ # The following form_builder classes are supported by the Sample class.
+ supported_field_types = [ CheckboxField, SelectField, TextField, WorkflowField ]
bulk_operations = Bunch( CHANGE_STATE = 'Change state',
SELECT_LIBRARY = 'Select data library and folder' )
api_collection_visible_keys = ( 'id', 'name' )
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -588,12 +588,8 @@ class RequestsCommon( BaseController, Us
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
except:
return invalid_id_redirect( trans, cntrller, request_id )
- events_list = []
- for event in request.events:
- events_list.append( ( event.state, time_ago( event.update_time ), event.comment ) )
return trans.fill_template( '/requests/common/view_request_history.mako',
cntrller=cntrller,
- events_list=events_list,
request=request )
@web.expose
@web.require_login( "edit email notification settings" )
@@ -777,7 +773,7 @@ class RequestsCommon( BaseController, Us
search_box=search_box )
@web.expose
@web.require_login( "sample events" )
- def sample_events( self, trans, cntrller, **kwd ):
+ def view_sample_history( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
status = params.get( 'status', 'done' )
message = util.restore_text( params.get( 'message', '' ) )
@@ -786,15 +782,8 @@ class RequestsCommon( BaseController, Us
sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( sample_id ) )
except:
return invalid_id_redirect( trans, cntrller, sample_id )
- events_list = []
- for event in sample.events:
- events_list.append( ( event.state.name,
- event.state.desc,
- time_ago( event.update_time ),
- event.comment ) )
- return trans.fill_template( '/requests/common/sample_events.mako',
+ return trans.fill_template( '/requests/common/view_sample_history.mako',
cntrller=cntrller,
- events_list=events_list,
sample=sample )
@web.expose
@web.require_login( "add sample" )
@@ -1054,9 +1043,9 @@ class RequestsCommon( BaseController, Us
# selected sets of samples. If samples are selected, the sample_operation param
# will have a value other than 'none', and the samples param will be a list of
# encoded sample ids. There are currently only 2 multi-select operations;
- # 'Change state' and 'Select data library and folder'. If sample_operation is
- # 'none, then the samples param will be a list of sample objects.
- if sample_operation == 'Change state':
+ # model.Sample.bulk_operations.CHANGE_STATE and model.sample.bulk_operations.SELECT_LIBRARY.
+ # If sample_operation is 'none, then the samples param will be a list of sample objects.
+ if sample_operation == trans.model.Sample.bulk_operations.CHANGE_STATE:
sample_state_id = params.get( 'sample_state_id', None )
if sample_state_id in [ None, 'none' ]:
message = "Select a new state from the <b>Change current state</b> list before clicking the <b>Save</b> button."
@@ -1090,7 +1079,7 @@ class RequestsCommon( BaseController, Us
cntrller=cntrller,
action='update_request_state',
request_id=trans.security.encode_id( request.id ) ) )
- elif sample_operation == 'Select data library and folder':
+ elif sample_operation == trans.model.sample.bulk_operations.SELECT_LIBRARY:
# TODO: fix the code so that the sample_operation_select_field does not use
# sample_0_library_id as it's name. it should use something like sample_operation_library_id
# and sample_operation_folder_id because the name sample_0_library_id should belong to the
--- a/lib/galaxy/web/controllers/forms.py
+++ b/lib/galaxy/web/controllers/forms.py
@@ -64,12 +64,12 @@ class FormsGrid( grids.Grid ):
]
class Forms( BaseController ):
- # Empty form field
+ # Empty TextField
empty_field = { 'label': '',
'helptext': '',
'visible': True,
'required': False,
- 'type': BaseField.form_field_types()[0],
+ 'type': model.TextField.__name__,
'selectlist': [],
'layout': 'none',
'default': '' }
@@ -597,12 +597,12 @@ class Forms( BaseController ):
self.selectbox_options = []
# if the form is for defining samples, then use the sample field types
# which does not include TextArea & AddressField
- if form_type == trans.app.model.FormDefinition.types.SAMPLE:
- for ft in BaseField.sample_field_types():
- self.fieldtype.add_option(ft, ft)
+ if form_type == trans.model.FormDefinition.types.SAMPLE:
+ for ft in trans.model.Sample.supported_field_types:
+ self.fieldtype.add_option( ft.__name__, ft.__name__ )
else:
- for ft in BaseField.form_field_types():
- self.fieldtype.add_option(ft, ft)
+ for ft in trans.model.Request.supported_field_types:
+ self.fieldtype.add_option( ft.__name__, ft__name__ )
self.required = SelectField('field_required_'+str(index), display='radio')
self.required.add_option('Required', 'required')
self.required.add_option('Optional', 'optional', selected=True)
@@ -632,22 +632,22 @@ class Forms( BaseController ):
field[ 'selectlist' ] = ['', '']
# if the form is for defining samples, then use the sample field types
# which does not include TextArea & AddressField
- if form_type == trans.app.model.FormDefinition.types.SAMPLE:
- for ft in BaseField.sample_field_types():
- if ft == field['type']:
- self.fieldtype.add_option(ft, ft, selected=True)
+ if form_type == trans.model.FormDefinition.types.SAMPLE:
+ for ft in trans.model.Sample.supported_field_types:
+ if ft.__name__ == field[ 'type' ]:
+ self.fieldtype.add_option( ft.__name__, ft__name__, selected=True )
if ft == 'SelectField':
- self.selectbox_ui(field)
+ self.selectbox_ui( field )
else:
- self.fieldtype.add_option(ft, ft)
+ self.fieldtype.add_option( ft.__name__, ft.__name__ )
else:
- for ft in BaseField.form_field_types():
- if ft == field['type']:
- self.fieldtype.add_option(ft, ft, selected=True)
+ for ft in trans.model.Request.supported_field_types:
+ if ft.__name__ == field[ 'type' ]:
+ self.fieldtype.add_option( ft.__name__, ft.__name__, selected=True )
if ft == 'SelectField':
- self.selectbox_ui(field)
+ self.selectbox_ui( field )
else:
- self.fieldtype.add_option(ft, ft)
+ self.fieldtype.add_option( ft.__name__, ft.__name__ )
# required/optional
if field['required'] == 'required':
self.required = SelectField('field_required_'+str(self.index), display='radio')
--- a/templates/admin/requests/create_request_type.mako
+++ b/templates/admin/requests/create_request_type.mako
@@ -39,7 +39,7 @@
<div style="clear: both"></div></div>
%endfor
- <div class="toolFormTitle">Possible sample states</div>
+ <div class="toolFormTitle">Sample states</div>
%if len(rt_states_widgets):
%for index, info in enumerate(rt_states_widgets):
${render_state( index, info[0], info[1] )}
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -160,7 +160,7 @@
%if is_unsubmitted:
<td>Unsubmitted</td>
%else:
- <td valign="top"><a href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
+ <td valign="top"><a href="${h.url_for( controller='requests_common', action='view_sample_history', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${sample.state.name}</a></td>
%endif
%else:
<td></td>
@@ -334,7 +334,7 @@
%if is_unsubmitted:
<td>Unsubmitted</td>
%else:
- <td><a id="sampleState-${sample.id}" href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${render_sample_state( sample )}</a></td>
+ <td><a id="sampleState-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_history', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${render_sample_state( sample )}</a></td>
%endif
%if sample_widget_library and library_cntrller is not None:
<td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller=library_cntrller, id=trans.security.encode_id( sample_widget_library.id ) )}">${sample_widget_library.name}</a></td>
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1536,7 +1536,7 @@ class TwillTestCase( unittest.TestCase )
self.visit_url( "%s/requests_common/view_request_history?cntrller=%s&id=%s" % ( self.url, cntrller, request_id ) )
self.check_page( strings_displayed, strings_displayed_count, strings_not_displayed )
def view_sample_history( self, cntrller, sample_id, strings_displayed=[], strings_displayed_count=[], strings_not_displayed=[] ):
- self.visit_url( "%s/requests_common/sample_events?cntrller=%s&sample_id=%s" % ( self.url, cntrller, sample_id ) )
+ self.visit_url( "%s/requests_common/view_sample_history?cntrller=%s&sample_id=%s" % ( self.url, cntrller, sample_id ) )
self.check_page( strings_displayed, strings_displayed_count, strings_not_displayed )
def edit_basic_request_info( self, cntrller, request_id, name, new_name='', new_desc='', new_fields=[],
strings_displayed=[], strings_displayed_after_submit=[] ):
--- a/templates/requests/common/edit_basic_request_info.mako
+++ b/templates/requests/common/edit_basic_request_info.mako
@@ -8,7 +8,6 @@
is_unsubmitted = request.is_unsubmitted
can_add_samples = is_unsubmitted
can_reject = is_admin and is_submitted
- can_select_datasets = is_admin and ( is_complete or is_submitted )
can_submit_request = request.samples and is_unsubmitted
%>
@@ -24,9 +23,6 @@
%if can_reject:
<a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
- %if can_select_datasets:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
- %endif
</div></ul>
--- /dev/null
+++ b/templates/requests/common/view_sample_history.mako
@@ -0,0 +1,38 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<% from galaxy.web.framework.helpers import time_ago %>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<h3>History of sample "${sample.name}"</h3>
+
+<div class="toolForm">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>State</th>
+ <th>Description</th>
+ <th>Last Updated</th>
+ <th>Comments</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for event in sample.events:
+ <tr>
+ <td><b>${event.state.name}</b></td>
+ <td>${event.state.desc}</td>
+ <td>${time_ago( event.update_time )}</td>
+ <td>${event.comment}</td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+</div>
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -44,8 +44,6 @@ class Configuration( object ):
# web API
self.enable_api = string_as_bool( kwargs.get( 'enable_api', False ) )
self.enable_openid = string_as_bool( kwargs.get( 'enable_openid', False ) )
- # Communication with a sequencer
- self.enable_sequencer_communication = string_as_bool( kwargs.get( 'enable_sequencer_communication', False ) )
# dataset Track files
self.track_store_path = kwargs.get( "track_store_path", "${extra_files_path}/tracks")
self.tool_path = resolve_path( kwargs.get( "tool_path", "tools" ), self.root )
--- a/templates/requests/common/view_request_history.mako
+++ b/templates/requests/common/view_request_history.mako
@@ -2,6 +2,8 @@
<%namespace file="/message.mako" import="render_msg" /><%
+ from galaxy.web.framework.helpers import time_ago
+
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
is_complete = request.is_complete
is_submitted = request.is_submitted
@@ -41,16 +43,16 @@
<thead><tr><th>State</th>
- <th>Last Update</th>
+ <th>Last Updated</th><th>Comments</th></tr></thead><tbody>
- %for state, updated, comments in events_list:
- <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><b><a>${state}</a></b></td>
- <td><a>${updated}</a></td>
- <td><a>${comments}</a></td>
+ %for event in request.events:
+ <tr>
+ <td><b>${event.state}</b></td>
+ <td>${time_ago( event.update_time )}</td>
+ <td>${event.comment}</td></tr>
%endfor
</tbody>
--- a/templates/requests/common/sample_events.mako
+++ /dev/null
@@ -1,44 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<%def name="title()">Events for Sample ${sample.name}</%def>
-
-<h2>Events for Sample "${sample.name}"</h2>
-<ul class="manage-table-actions">
- <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
-</ul>
-<h3>Sequencing Request "${sample.request.name}"</h3>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<div class="toolForm">
- <div class="form-row">
- <div class="toolParamHelp" style="clear: both;">
- <b>Possible states: </b>
- <% states = " > ".join([ ss.name for ss in sample.request.type.states ]) %>
- ${states}
- </div>
- </div>
- <table class="grid">
- <thead>
- <tr>
- <th>State</th>
- <th>Description</th>
- <th>Last Update</th>
- <th>Comments</th>
- </tr>
- </thead>
- <tbody>
- %for state, desc, updated, comments in events_list:
- <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><b><a>${state}</a></b></td>
- <td><a>${desc}</a></td>
- <td><a>${updated}</a></td>
- <td><a>${comments}</a></td>
- </tr>
- %endfor
- </tbody>
- </table>
-</div>
1
0
galaxy-dist commit 56431b214df1: Don't 'use strict' as FF4 beta doesn't support it
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1289944688 18000
# Node ID 56431b214df16653a966b96bf399c7646da267b8
# Parent 394d8186f666b506cd0a93aefb7a079e0c9ec59b
Don't 'use strict' as FF4 beta doesn't support it
--- a/static/scripts/jquery.jstore.js
+++ b/static/scripts/jquery.jstore.js
@@ -15,7 +15,7 @@
* http://creativecommons.org/licenses/by/3.0/us
*/
-"use strict";
+//"use strict";
/*global Class, window, jQuery, ActiveXObject, google */
--- a/static/scripts/class.js
+++ b/static/scripts/class.js
@@ -5,7 +5,7 @@
* Inspired by base2 and Prototype
*/
-"use strict";
+//"use strict";
(function () {
--- a/static/scripts/packed/jquery.jstore.js
+++ b/static/scripts/packed/jquery.jstore.js
@@ -14,4 +14,4 @@
* Licensed under the Creative Commons Attribution 3.0 United States License:
* http://creativecommons.org/licenses/by/3.0/us
*/
-"use strict";(function(i,n){var h="JSTORE_ENGINE_UNSTABLE",t="JSTORE_UNKNOWN_ENGINE_REQUESTED",r="JSTORE_ENGINE_NAMESPACE_COLLISION",j="JSTORE_RESOURCE_NAMESPACE_COLLISION",m="JSTORE_ENGINE_UNAVAILABLE",o="JSTORE_INVALID_FLAVOR",f=(function(){try{return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}catch(I){return(/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/)}}()),b="jstore-html5-local",y="jstore-html5-sql",F="jstore-flash",G="jstore-google-gears",A="jstore-msie",u,E={},D={},C={},c=false,d={},q={project:undefined,flash:"jStore.Flash.html",json:"browser.json.js"},l;function z(I){switch(I){case b:case y:case F:case G:case A:return true;default:return false}}function g(I,J){return !I?false:I.constructor.toString().match(new RegExp(J+"\\(\\)","i"))!==null}function s(K,I,J){if(g(K,"Function")){return K.apply(I||E,g(J,"Array")?J:[J])}}function p(J,I){i.ajax({url:J,complete:I||i.noop(),type:"GET",dataType:"script",cache:false})}func
tion x(I){if(I===undefined){return""}if(g(I,"Object")||g(I,"Array")||g(I,"Function")){return JSON.stringify(I)}return I}function k(I){return f.test(I)?JSON.parse(I):I}function w(I){return I.replace(/^\s+|\s+$/g,"")}function e(I,J,K){if(!z(I)){throw o}if(K[I]!==undefined){throw r}if(s(K)===true){E.available[I]=true;J.flavor=I;D[I]=u.extend(J)}else{E.available[I]=false;E.enginePriority=i.map(E.enginePriority,function(L){if(L===I){return null}else{return L}})}}function v(){if(E.isReady){return}if((c&&E.isFlashReady)||!c){E.isReady=true;E.trigger("jstore-ready",[C[l]])}}function a(){E.create(E.enginePriority[0],undefined,"best-fit")}function H(){try{var J=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");try{J.AllowScriptAccess="always"}catch(L){return"6,0,0"}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(K){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(navi
gator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(I){}}return"0,0,0"}function B(I){var N=H().match(/\d+/g),L=I.match(/\d+/g),J=0,K,M;for(;J<3;J++){K=parseInt(N[J],10);M=parseInt(L[J],10);if(K<M){return false}else{if(K>M){return true}}}return true}i.extend(E,{enginePriority:[b,y,F,A],available:{},isReady:false,isFlashReady:false,flavors:{local:b,sql:y,flash:F,gears:G,msie:A},init:function(J,K,I){i.extend(q,{project:J},K);i(function(){if(n.JSON===undefined){p(q.json)}if(I!==undefined){E.create(I,J,"default")}else{a()}});return E},create:function(I,M,J){M=M||q.project||location.hostname.replace(/\./g,"-")||"unknown";if(!z(I)){throw o}if(D[I]===undefined){throw m}var L=(J!==undefined?J+".":"")+M+"."+I,K;if(C[L]!==undefined){throw j}K=C[L]=new D[I](M,L);K.ready(function(){E.trigger("jstore-engine-ready",[K])});if(I===F&&!E.isFlashReady){if(l===undefined){c=true}n.jstore_ready=function(){E.isFl
ashReady=true;E.trigger("flash-ready");if(l===undefined){v()}n.flash_ready=undefined};n.jstore_error=function(N){E.trigger("jstore-error",["JSTORE_FLASH_EXCEPTION",null,N])};i('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+q.flash+'"></iframe>').appendTo("body")}else{if(l===undefined){l=L;v()}}return K},engine:function(I){return C[I]},activeEngine:function(I){if(I!==undefined){if(C[I]===undefined){throw t}else{l=I}}return C[l]},bind:function(J,K,I){I=I||"jstore";if(d[I]===undefined){d[I]={}}if(d[I][J]===undefined){d[I][J]=[K]}else{d[I][J].push(K)}return E},trigger:function(K,J,I){I=I||"jstore";if(d[I]!==undefined){if(d[I][K]!==undefined){i.each(d[I][K],function(){s(this,E,J)})}}return E},error:function(I){E.bind("jstore-error",I)},ready:function(I){if(E.isReady){s(I)}else{E.bind("jstore-ready",I)}return E},engineReady:function(I){if(E.isReady){s(I)}else{E.bind("jstore-engine-ready",I)}return E},store:func
tion(I,J){return J===undefined?E.get(I):E.set(I,J)},remove:function(I){return E.activeEngine().remove(I)},get:function(I){return E.activeEngine().get(I)},set:function(I,J){return E.activeEngine().set(I,J)}});u=Class.extend({project:undefined,jri:undefined,flavor:undefined,database:undefined,data:undefined,limit:undefined,isReady:undefined,init:function(J,I){this.project=J;this.jri=I;this.data={};this.isReady=false;this.updateCache()},updateCache:function(){this.isReady=true;this.trigger("engine-ready",[this])},bind:function(I,J){E.bind(I,J,this.jri)},trigger:function(J,I){E.trigger(J,I,this.jri)},ready:function(I){if(this.isReady){s(I,this)}else{this.bind("engine-ready",I)}},get:function(I){this.__interruptAccess();return this.data[I]},set:function(I,J){this.__interruptAccess();I=w(I);try{this.__set(I,J)}catch(K){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,K])}this.data[I]=J;return J},remove:function(J){this.__interruptAccess();J=w(J);try{this.__remove(J)}cat
ch(K){E.trigger("jstore-error",["JSTORE_REMOVE_FAILURE",this.jri,K])}var I=this.data[J];this.data[J]=undefined;return I},__interruptAccess:function(){if(!this.isReady){throw h}},__set:function(I,J){return},__remove:function(I){return}});i.extend(i.fn,{store:function(I,J){if(J===undefined){E.get(I)}else{E.set(I,J)}return this},removeStore:function(I){E.activeEngine().remove(I);return this},getStore:function(I){return E.activeEngine().get(I)},setStore:function(I,J){E.activeEngine().set(I,J);return this}});n.jStore=i.jStore=E;e(b,{limit:parseInt(500000,16),init:function(J,I){this.database=n.globalStorage===undefined?n.localStorage:n.globalStorage[location.hostname];this._super(J,I)},updateCache:function(){var J,K;for(J in this.database){var I=false;if(this.database.hasOwnProperty){if(this.database.hasOwnProperty(J)){I=true}}else{if(this.database.getItem(J)!==null){I=true}}if(I){K=this.database.getItem(J);this.data[J]=k(K&&K.value?K.value:K)}}this._super()},__set:function(I,J){t
his.database.setItem(I,x(J))},__remove:function(I){this.database.removeItem(I)}},function(){return n.localStorage!==undefined||n.globalStorage!==undefined});e(y,{limit:parseInt(32000,16),init:function(J,I){this.database=n.openDatabase("jstore-"+J,"1.0",J,this.limit);if(!this.database){throw"JSTORE_SQL_NO_DB"}this.database.transaction(function(K){K.executeSql("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this._super(J,I)},updateCache:function(){var I=this,J=this._super;this.database.transaction(function(K){K.executeSql("SELECT k,v FROM jstore",[],function(O,L){var N=L.rows,M=0,P;for(;M<N.length;++M){P=N.item(M);I.data[P.k]=k(P.v)}J.apply(I)})})},__set:function(I,J){this.database.transaction(function(K){K.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)])})},__remove:function(I){this.database.transaction(function(J){J.executeSql("DELETE FROM jstore WHERE k = ?",[I])})}},function(){return n.openDatabase!==unde
fined});e(F,{limit:-1,init:function(K,J){var I=this;E.bind("flash-ready",function(){I.__flashReadyListener()});this._super(K,J)},updateCache:function(I){if(I===true){var J,K=this.database.jstore_get_all();for(J in K){if(K.hasOwnProperty(J)){this.data[J]=k(this.database.jstore_get(J))}}this._super()}},__set:function(I,J){if(!this.database.jstore_set(I,x(J))){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,"Flash Exception"])}},__remove:function(I){this.database.jstore_remove(I)},__flashReadyListener:function(){var I=i("#jStoreFlashFrame")[0],J;if(I.Document!==undefined&&g(I.Document.jStoreFlash.jstore_get,"Function")){this.database=I.Document.jStoreFlash}else{if(I.contentWindow&&I.contentWindow.document){J=i(I.contentWindow.document);if(g(i("object",J)[0].jstore_get,"Function")){this.database=i("object",J)[0]}else{if(g(i("embed",J)[0].jstore_get,"Function")){this.database=i("embed",J)[0]}}}}if(this.database===undefined){throw"JSTORE_FLASH_REFERENCE_ISSUE"}else{thi
s.updateCache(true)}}},function(){return B("9.0.0")});e(G,{limit:-1,init:function(J,I){this.database=google.gears.factory.create("beta.database");this.database.open("jstore-"+J);this.database.execute("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)");this._super(J,I)},updateCache:function(){var I=this.database.execute("SELECT k,v FROM jstore");while(I.isValidRow()){this.data[I.field(0)]=k(I.field(1));I.next()}I.close();this._super()},__set:function(I,J){this.database.execute("BEGIN");this.database.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)]);this.database.execute("COMMIT")},__remove:function(I){this.database.execute("BEGIN");this.database.execute("DELETE FROM jstore WHERE k = ?",[I]);this.database.execute("COMMIT")}},function(){return n.google!==undefined&&n.google.gears!==undefined});e(A,{limit:parseInt(10000,16),init:function(J,I){this.database=i('<div style="display:none;behavior:url(\'#default#userData\')"
id="jstore-'+J+'"></div>').appendTo(document.body).get(0);this._super(J,I)},updateCache:function(){this.database.load(this.project);var K=document.getElementById("jstore-"+this.project),L=K.XMLDocument,I,J=0;if(L&&L.documentElement&&L.documentElement.attributes){I=L.documentElement;for(;J<I.attributes.length;++J){this.data[I.attributes.item(J).nodeName]=k(I.attributes.item(J).nodeValue)}}this._super()},__set:function(I,J){this.database.setAttribute(I,x(J));this.database.save(this.project)},__remove:function(I){this.database.removeAttribute(I);this.database.save(this.project)}},function(){return n.ActiveXObject!==undefined})}(jQuery,window));
+(function(i,n){var h="JSTORE_ENGINE_UNSTABLE",t="JSTORE_UNKNOWN_ENGINE_REQUESTED",r="JSTORE_ENGINE_NAMESPACE_COLLISION",j="JSTORE_RESOURCE_NAMESPACE_COLLISION",m="JSTORE_ENGINE_UNAVAILABLE",o="JSTORE_INVALID_FLAVOR",f=(function(){try{return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}catch(I){return(/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/)}}()),b="jstore-html5-local",y="jstore-html5-sql",F="jstore-flash",G="jstore-google-gears",A="jstore-msie",u,E={},D={},C={},c=false,d={},q={project:undefined,flash:"jStore.Flash.html",json:"browser.json.js"},l;function z(I){switch(I){case b:case y:case F:case G:case A:return true;default:return false}}function g(I,J){return !I?false:I.constructor.toString().match(new RegExp(J+"\\(\\)","i"))!==null}function s(K,I,J){if(g(K,"Function")){return K.apply(I||E,g(J,"Array")?J:[J])}}function p(J,I){i.ajax({url:J,complete:I||i.noop(),type:"GET",dataType:"script",cache:false})}function x(I){if(
I===undefined){return""}if(g(I,"Object")||g(I,"Array")||g(I,"Function")){return JSON.stringify(I)}return I}function k(I){return f.test(I)?JSON.parse(I):I}function w(I){return I.replace(/^\s+|\s+$/g,"")}function e(I,J,K){if(!z(I)){throw o}if(K[I]!==undefined){throw r}if(s(K)===true){E.available[I]=true;J.flavor=I;D[I]=u.extend(J)}else{E.available[I]=false;E.enginePriority=i.map(E.enginePriority,function(L){if(L===I){return null}else{return L}})}}function v(){if(E.isReady){return}if((c&&E.isFlashReady)||!c){E.isReady=true;E.trigger("jstore-ready",[C[l]])}}function a(){E.create(E.enginePriority[0],undefined,"best-fit")}function H(){try{var J=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");try{J.AllowScriptAccess="always"}catch(L){return"6,0,0"}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(K){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(navigator.plugins
["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(I){}}return"0,0,0"}function B(I){var N=H().match(/\d+/g),L=I.match(/\d+/g),J=0,K,M;for(;J<3;J++){K=parseInt(N[J],10);M=parseInt(L[J],10);if(K<M){return false}else{if(K>M){return true}}}return true}i.extend(E,{enginePriority:[b,y,F,A],available:{},isReady:false,isFlashReady:false,flavors:{local:b,sql:y,flash:F,gears:G,msie:A},init:function(J,K,I){i.extend(q,{project:J},K);i(function(){if(n.JSON===undefined){p(q.json)}if(I!==undefined){E.create(I,J,"default")}else{a()}});return E},create:function(I,M,J){M=M||q.project||location.hostname.replace(/\./g,"-")||"unknown";if(!z(I)){throw o}if(D[I]===undefined){throw m}var L=(J!==undefined?J+".":"")+M+"."+I,K;if(C[L]!==undefined){throw j}K=C[L]=new D[I](M,L);K.ready(function(){E.trigger("jstore-engine-ready",[K])});if(I===F&&!E.isFlashReady){if(l===undefined){c=true}n.jstore_ready=function(){E.isFlashReady=true
;E.trigger("flash-ready");if(l===undefined){v()}n.flash_ready=undefined};n.jstore_error=function(N){E.trigger("jstore-error",["JSTORE_FLASH_EXCEPTION",null,N])};i('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+q.flash+'"></iframe>').appendTo("body")}else{if(l===undefined){l=L;v()}}return K},engine:function(I){return C[I]},activeEngine:function(I){if(I!==undefined){if(C[I]===undefined){throw t}else{l=I}}return C[l]},bind:function(J,K,I){I=I||"jstore";if(d[I]===undefined){d[I]={}}if(d[I][J]===undefined){d[I][J]=[K]}else{d[I][J].push(K)}return E},trigger:function(K,J,I){I=I||"jstore";if(d[I]!==undefined){if(d[I][K]!==undefined){i.each(d[I][K],function(){s(this,E,J)})}}return E},error:function(I){E.bind("jstore-error",I)},ready:function(I){if(E.isReady){s(I)}else{E.bind("jstore-ready",I)}return E},engineReady:function(I){if(E.isReady){s(I)}else{E.bind("jstore-engine-ready",I)}return E},store:function(I,J){ret
urn J===undefined?E.get(I):E.set(I,J)},remove:function(I){return E.activeEngine().remove(I)},get:function(I){return E.activeEngine().get(I)},set:function(I,J){return E.activeEngine().set(I,J)}});u=Class.extend({project:undefined,jri:undefined,flavor:undefined,database:undefined,data:undefined,limit:undefined,isReady:undefined,init:function(J,I){this.project=J;this.jri=I;this.data={};this.isReady=false;this.updateCache()},updateCache:function(){this.isReady=true;this.trigger("engine-ready",[this])},bind:function(I,J){E.bind(I,J,this.jri)},trigger:function(J,I){E.trigger(J,I,this.jri)},ready:function(I){if(this.isReady){s(I,this)}else{this.bind("engine-ready",I)}},get:function(I){this.__interruptAccess();return this.data[I]},set:function(I,J){this.__interruptAccess();I=w(I);try{this.__set(I,J)}catch(K){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,K])}this.data[I]=J;return J},remove:function(J){this.__interruptAccess();J=w(J);try{this.__remove(J)}catch(K){E.trigg
er("jstore-error",["JSTORE_REMOVE_FAILURE",this.jri,K])}var I=this.data[J];this.data[J]=undefined;return I},__interruptAccess:function(){if(!this.isReady){throw h}},__set:function(I,J){return},__remove:function(I){return}});i.extend(i.fn,{store:function(I,J){if(J===undefined){E.get(I)}else{E.set(I,J)}return this},removeStore:function(I){E.activeEngine().remove(I);return this},getStore:function(I){return E.activeEngine().get(I)},setStore:function(I,J){E.activeEngine().set(I,J);return this}});n.jStore=i.jStore=E;e(b,{limit:parseInt(500000,16),init:function(J,I){this.database=n.globalStorage===undefined?n.localStorage:n.globalStorage[location.hostname];this._super(J,I)},updateCache:function(){var J,K;for(J in this.database){var I=false;if(this.database.hasOwnProperty){if(this.database.hasOwnProperty(J)){I=true}}else{if(this.database.getItem(J)!==null){I=true}}if(I){K=this.database.getItem(J);this.data[J]=k(K&&K.value?K.value:K)}}this._super()},__set:function(I,J){this.database.
setItem(I,x(J))},__remove:function(I){this.database.removeItem(I)}},function(){return n.localStorage!==undefined||n.globalStorage!==undefined});e(y,{limit:parseInt(32000,16),init:function(J,I){this.database=n.openDatabase("jstore-"+J,"1.0",J,this.limit);if(!this.database){throw"JSTORE_SQL_NO_DB"}this.database.transaction(function(K){K.executeSql("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this._super(J,I)},updateCache:function(){var I=this,J=this._super;this.database.transaction(function(K){K.executeSql("SELECT k,v FROM jstore",[],function(O,L){var N=L.rows,M=0,P;for(;M<N.length;++M){P=N.item(M);I.data[P.k]=k(P.v)}J.apply(I)})})},__set:function(I,J){this.database.transaction(function(K){K.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)])})},__remove:function(I){this.database.transaction(function(J){J.executeSql("DELETE FROM jstore WHERE k = ?",[I])})}},function(){return n.openDatabase!==undefined});e(F,{
limit:-1,init:function(K,J){var I=this;E.bind("flash-ready",function(){I.__flashReadyListener()});this._super(K,J)},updateCache:function(I){if(I===true){var J,K=this.database.jstore_get_all();for(J in K){if(K.hasOwnProperty(J)){this.data[J]=k(this.database.jstore_get(J))}}this._super()}},__set:function(I,J){if(!this.database.jstore_set(I,x(J))){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,"Flash Exception"])}},__remove:function(I){this.database.jstore_remove(I)},__flashReadyListener:function(){var I=i("#jStoreFlashFrame")[0],J;if(I.Document!==undefined&&g(I.Document.jStoreFlash.jstore_get,"Function")){this.database=I.Document.jStoreFlash}else{if(I.contentWindow&&I.contentWindow.document){J=i(I.contentWindow.document);if(g(i("object",J)[0].jstore_get,"Function")){this.database=i("object",J)[0]}else{if(g(i("embed",J)[0].jstore_get,"Function")){this.database=i("embed",J)[0]}}}}if(this.database===undefined){throw"JSTORE_FLASH_REFERENCE_ISSUE"}else{this.updateCache
(true)}}},function(){return B("9.0.0")});e(G,{limit:-1,init:function(J,I){this.database=google.gears.factory.create("beta.database");this.database.open("jstore-"+J);this.database.execute("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)");this._super(J,I)},updateCache:function(){var I=this.database.execute("SELECT k,v FROM jstore");while(I.isValidRow()){this.data[I.field(0)]=k(I.field(1));I.next()}I.close();this._super()},__set:function(I,J){this.database.execute("BEGIN");this.database.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)]);this.database.execute("COMMIT")},__remove:function(I){this.database.execute("BEGIN");this.database.execute("DELETE FROM jstore WHERE k = ?",[I]);this.database.execute("COMMIT")}},function(){return n.google!==undefined&&n.google.gears!==undefined});e(A,{limit:parseInt(10000,16),init:function(J,I){this.database=i('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-'+
J+'"></div>').appendTo(document.body).get(0);this._super(J,I)},updateCache:function(){this.database.load(this.project);var K=document.getElementById("jstore-"+this.project),L=K.XMLDocument,I,J=0;if(L&&L.documentElement&&L.documentElement.attributes){I=L.documentElement;for(;J<I.attributes.length;++J){this.data[I.attributes.item(J).nodeName]=k(I.attributes.item(J).nodeValue)}}this._super()},__set:function(I,J){this.database.setAttribute(I,x(J));this.database.save(this.project)},__remove:function(I){this.database.removeAttribute(I);this.database.save(this.project)}},function(){return n.ActiveXObject!==undefined})}(jQuery,window));
--- a/static/scripts/packed/class.js
+++ b/static/scripts/packed/class.js
@@ -4,4 +4,4 @@
* Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/)
* Inspired by base2 and Prototype
*/
-"use strict";(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=(typeof g[d]==="function"&&typeof f[d]==="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}}(d,g[d])):g[d])}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}}());
+(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=(typeof g[d]==="function"&&typeof f[d]==="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}}(d,g[d])):g[d])}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}}());
1
0
galaxy-dist commit a68c74ec8cfb: OpenID support for Galaxy.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1290006822 18000
# Node ID a68c74ec8cfbc641db4b6fe424e3f77b9f3c5d3c
# Parent 56431b214df16653a966b96bf399c7646da267b8
OpenID support for Galaxy.
--- a/eggs.ini
+++ b/eggs.ini
@@ -44,6 +44,7 @@ Paste = 1.6
PasteDeploy = 1.3.3
PasteScript = 1.7.3
pexpect = 2.4
+python_openid = 2.2.5
Routes = 1.12.3
SQLAlchemy = 0.5.6
sqlalchemy_migrate = 0.5.4
--- /dev/null
+++ b/templates/user/openid_manage.mako
@@ -0,0 +1,17 @@
+## Template generates a grid that enables user to select items.
+<%namespace file="../grid_base.mako" import="make_grid" />
+<%namespace file="login.mako" import="render_openid_form" />
+
+<%inherit file="../grid_base.mako" />
+
+<%def name="grid_body( grid )">
+ ${make_grid( grid )}
+ <h2>Associate more OpenIDs</h2>
+ ${render_openid_form( kwargs['referer'], True, kwargs['openid_providers'] )}
+</%def>
+
+<%def name="center_panel()">
+ <div style="margin: 1em;">
+ ${grid_body( grid )}
+ </div>
+</%def>
Binary file static/images/openid-16x16.gif has changed
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1953,6 +1953,12 @@ class UserAddress( object ):
html = html + '<br/>' + 'Phone: ' + self.phone
return html
+class UserOpenID( object ):
+ def __init__( self, user=None, session=None, openid=None ):
+ self.user = user
+ self.session = session
+ self.openid = openid
+
class Page( object ):
def __init__( self ):
self.id = None
--- a/templates/user/index.mako
+++ b/templates/user/index.mako
@@ -15,6 +15,9 @@
%if trans.app.config.enable_api:
<li><a href="${h.url_for( controller='user', action='api_keys' )}">${_('Manage your API Keys')}</a> for new histories</li>
%endif
+ %if trans.app.config.enable_openid:
+ <li><a href="${h.url_for( controller='user', action='openid_manage' )}">${ ('Manage OpenIDs')}</a> linked to your account</li>
+ %endif
%else:
<li><a href="${h.url_for( controller='user', action='show_info', webapp='community' )}">${_('Manage your information')}</a></li>
%endif
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0062_user_openid_table.py
@@ -0,0 +1,48 @@
+"""
+Migration script to create table for associating sessions and users with
+OpenIDs.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import datetime
+now = datetime.datetime.utcnow
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+# Table to add
+
+UserOpenID_table = Table( "galaxy_user_openid", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, index=True, default=now, onupdate=now ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "openid", TEXT, index=True, unique=True ),
+ )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create galaxy_user_openid table
+ try:
+ UserOpenID_table.create()
+ except Exception, e:
+ log.debug( "Creating galaxy_user_openid table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop galaxy_user_openid table
+ try:
+ UserOpenID_table.drop()
+ except Exception, e:
+ log.debug( "Dropping galaxy_user_openid table failed: %s" % str( e ) )
--- a/templates/user/login.mako
+++ b/templates/user/login.mako
@@ -1,23 +1,77 @@
-<%inherit file="/base.mako"/>
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ if context.get('webapp'):
+ webapp = context.get('webapp')
+ else:
+ webapp = 'galaxy'
+ return '/webapps/%s/base_panels.mako' % webapp
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view=active_view
+ self.message_box_visible=False
+%>
+</%def>
+
<%namespace file="/message.mako" import="render_msg" />
-%if redirect_url:
- <script type="text/javascript">
- top.location.href = '${redirect_url}';
- </script>
-%endif
+<%def name="center_panel()">
+ ${body()}
+</%def>
-%if not redirect_url and message:
- ${render_msg( message, status )}
-%endif
+<%def name="body()">
-%if not trans.user:
+ %if redirect_url:
+ <script type="text/javascript">
+ top.location.href = '${redirect_url}';
+ </script>
+ %endif
+
+ %if context.get('use_panels'):
+ <div style="margin: 1em;">
+ %else:
+ <div>
+ %endif
+
+ %if message:
+ ${render_msg( message, status )}
+ %endif
+
+ %if not trans.user:
+
+ ${render_login_form()}
+
+ %if trans.app.config.enable_openid:
+ <br/>
+ ${render_openid_form( referer, False, openid_providers )}
+ %endif
+
+ %endif
+
+ </div>
+
+</%def>
+
+<%def name="render_login_form( form_action=None )">
+
+ <%
+ if form_action is None:
+ form_action = h.url_for( controller='user', action='login', use_panels=use_panels )
+ %>
+
%if header:
${header}
%endif
<div class="toolForm"><div class="toolFormTitle">Login</div>
- <form name="login" id="login" action="${h.url_for( controller='user', action='login' )}" method="post" >
+ <form name="login" id="login" action="${form_action}" method="post" ><div class="form-row"><label>Email address:</label><input type="text" name="email" value="${email}" size="40"/>
@@ -36,4 +90,32 @@
</div></form></div>
-%endif
+
+</%def>
+
+<%def name="render_openid_form( referer, auto_associate, openid_providers )">
+
+ <div class="toolForm">
+ <div class="toolFormTitle">OpenID Login</div>
+ <form name="openid" id="openid" action="${h.url_for( controller='user', action='openid_auth' )}" method="post" >
+ <div class="form-row">
+ <label>OpenID URL:</label>
+ <input type="text" name="openid_url" size="60" style="background-image:url('${h.url_for( '/static/images/openid-16x16.gif' )}' ); background-repeat: no-repeat; padding-right: 20px; background-position: 99% 50%;"/>
+ <input type="hidden" name="webapp" value="${webapp}" size="40"/>
+ <input type="hidden" name="referer" value="${referer}" size="40"/>
+ <input type="hidden" name="auto_associate" value="${auto_associate}" size="40"/>
+ </div>
+ <div class="form-row">
+ Or, authenticate with your <select name="openid_provider">
+ %for provider in openid_providers.keys():
+ <option>${provider}</option>
+ %endfor
+ </select> account.
+ </div>
+ <div class="form-row">
+ <input type="submit" name="login_button" value="Login"/>
+ </div>
+ </form>
+ </div>
+
+</%def>
--- a/lib/galaxy/eggs/__init__.py
+++ b/lib/galaxy/eggs/__init__.py
@@ -321,6 +321,7 @@ class GalaxyConfig( object ):
"pbs_python": lambda: "pbs" in self.config.get( "app:main", "start_job_runners" ).split(","),
"threadframe": lambda: self.config.get( "app:main", "use_heartbeat" ),
"guppy": lambda: self.config.get( "app:main", "use_memdump" ),
+ "python_openid": lambda: self.config.get( "app:main", "enable_openid" ),
"GeneTrack": lambda: sys.version_info[:2] >= ( 2, 5 ),
"pysam": check_pysam()
}.get( egg_name, lambda: True )()
--- /dev/null
+++ b/templates/user/openid_associate.mako
@@ -0,0 +1,75 @@
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ if context.get('webapp'):
+ webapp = context.get('webapp')
+ else:
+ webapp = 'galaxy'
+ return '/webapps/%s/base_panels.mako' % webapp
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view=active_view
+ self.message_box_visible=False
+%>
+</%def>
+
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="login.mako" import="render_login_form" />
+<%namespace file="register.mako" import="render_registration_form" />
+
+<%def name="center_panel()">
+ ${body()}
+</%def>
+
+<%def name="body()">
+
+ %if context.get('use_panels'):
+ <div style="margin: 1em;">
+ %else:
+ <div>
+ %endif
+
+ %if message:
+ ${render_msg( message, status )}
+ %endif
+
+ <h2>OpenID Account Association</h2>
+ <div>
+ OpenIDs must be associated with a Galaxy account before they can be used for authentication. This only needs to be done once per OpenID. You may associate your OpenID with an existing Galaxy account, or create a new one.
+ </div>
+ <br/>
+
+ %if len( openids ) > 1:
+ <div>
+ The following OpenIDs will be associated with the account chosen or created below.
+ <ul>
+ %for openid in openids:
+ <li>${openid.openid}</li>
+ %endfor
+ </ul>
+ </div>
+ %else:
+ <div>
+ The OpenID <strong>${openids[0].openid}</strong> will be associated with the account chosen or created.
+ </div>
+ %endif
+ <br/>
+
+ <% form_action = h.url_for( use_panels=use_panels ) %>
+
+ ${render_login_form( form_action=form_action )}
+
+ <br/>
+
+ ${render_registration_form( form_action=form_action )}
+
+ </div>
+
+</%def>
--- a/templates/user/register.mako
+++ b/templates/user/register.mako
@@ -22,8 +22,18 @@
## An admin user may be creating a new user account, in which case we want to display the registration form.
## But if the current user is not an admin user, then don't display the registration form.
%if trans.user_is_admin() or not trans.user:
+ ${render_registration_form()}
+%endif
+
+<%def name="render_registration_form( form_action=None )">
+
+ <%
+ if form_action is None:
+ form_action = h.url_for( controller='user', action='create', admin_view=admin_view )
+ %>
+
<div class="toolForm">
- <form name="registration" id="registration" action="${h.url_for( controller='user', action='create', admin_view=admin_view )}" method="post" >
+ <form name="registration" id="registration" action="${form_action}" method="post" ><div class="toolFormTitle">Create account</div><div class="form-row"><label>Email address:</label>
@@ -83,4 +93,5 @@
</div></form></div>
-%endif
+
+</%def>
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -324,6 +324,10 @@ use_interactive = True
# WYSIWYG editor that is very similar to a word processor.
#enable_pages = False
+# Enable authentication via OpenID. Allows users to log in to their Galaxy
+# account by authenticating with an OpenID provider.
+#enable_openid = False
+
# Enable the (experimental! beta!) Web API. Documentation forthcoming.
#enable_api = False
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -68,6 +68,15 @@ UserAddress.table = Table( "user_address
Column( "deleted", Boolean, index=True, default=False ),
Column( "purged", Boolean, index=True, default=False ) )
+UserOpenID.table = Table( "galaxy_user_openid", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "update_time", DateTime, index=True, default=now, onupdate=now ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "openid", TEXT, index=True, unique=True ),
+ )
+
History.table = Table( "history", metadata,
Column( "id", Integer, primary_key=True),
Column( "create_time", DateTime, default=now ),
@@ -968,6 +977,17 @@ assign_mapper( context, UserAddress, Use
order_by=desc(UserAddress.table.c.update_time)),
) )
+assign_mapper( context, UserOpenID, UserOpenID.table,
+ properties=dict(
+ session=relation( GalaxySession,
+ primaryjoin=( UserOpenID.table.c.session_id == GalaxySession.table.c.id ),
+ backref='openids',
+ order_by=desc( UserOpenID.table.c.update_time ) ),
+ user=relation( User,
+ primaryjoin=( UserOpenID.table.c.user_id == User.table.c.id ),
+ backref='openids',
+ order_by=desc( UserOpenID.table.c.update_time ) ) ) )
+
assign_mapper( context, ValidationError, ValidationError.table )
--- a/templates/display_common.mako
+++ b/templates/display_common.mako
@@ -85,6 +85,8 @@
class_plural = "Forms"
elif a_class == model.RequestType:
class_plural = "sequencer configurations"
+ elif a_class == model.UserOpenID:
+ class_plural = "OpenIDs"
else:
class_plural = a_class.__name__ + "s"
return class_plural
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -60,6 +60,10 @@ class UniverseApplication( object ):
self.heartbeat = None
self.memdump = None
self.memory_usage = None
+ # Container for OpenID authentication routines
+ if self.config.enable_openid:
+ from galaxy.web.framework import openid_manager
+ self.openid_manager = openid_manager.OpenIDManager( self.config.openid_consumer_cache_path )
# Start the heartbeat process if configured and available
if self.config.use_heartbeat:
from galaxy.util import heartbeat
--- /dev/null
+++ b/lib/galaxy/web/framework/openid_manager.py
@@ -0,0 +1,53 @@
+"""
+Mange the OpenID consumer and related data stores.
+"""
+
+import os, pickle, logging
+
+from galaxy import eggs
+eggs.require( 'python-openid' )
+
+import openid
+from openid import oidutil
+from openid.store import filestore
+from openid.consumer import consumer
+from openid.extensions import sreg
+
+log = logging.getLogger( __name__ )
+def oidlog( message, level=0 ):
+ log.debug( message )
+oidutil.log = oidlog
+
+class OpenIDManager( object ):
+ def __init__( self, cache_path ):
+ self.session_path = os.path.join( cache_path, 'session' )
+ self.store_path = os.path.join( cache_path, 'store' )
+ for dir in self.session_path, self.store_path:
+ if not os.path.exists( dir ):
+ os.makedirs( dir )
+ self.store = filestore.FileOpenIDStore( self.store_path )
+ def get_session( self, trans ):
+ session_file = os.path.join( self.session_path, str( trans.galaxy_session.id ) )
+ if not os.path.exists( session_file ):
+ pickle.dump( dict(), open( session_file, 'w' ) )
+ return pickle.load( open( session_file ) )
+ def persist_session( self, trans, oidconsumer ):
+ session_file = os.path.join( self.session_path, str( trans.galaxy_session.id ) )
+ pickle.dump( oidconsumer.session, open( session_file, 'w' ) )
+ def get_consumer( self, trans ):
+ return consumer.Consumer( self.get_session( trans ), self.store )
+ def add_sreg( self, trans, request, required=None, optional=None ):
+ if required is None:
+ required = []
+ if optional is None:
+ optional = []
+ sreg_request = sreg.SRegRequest( required=required, optional=optional )
+ request.addExtension( sreg_request )
+ def get_sreg( self, info ):
+ return sreg.SRegResponse.fromSuccessResponse( info )
+
+ # so I don't have to expose all of openid.consumer.consumer
+ FAILURE = consumer.FAILURE
+ SUCCESS = consumer.SUCCESS
+ CANCEL = consumer.CANCEL
+ SETUP_NEEDED = consumer.SETUP_NEEDED
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -39,9 +39,11 @@ class Configuration( object ):
# Where dataset files are stored
self.file_path = resolve_path( kwargs.get( "file_path", "database/files" ), self.root )
self.new_file_path = resolve_path( kwargs.get( "new_file_path", "database/tmp" ), self.root )
+ self.openid_consumer_cache_path = resolve_path( kwargs.get( "openid_consumer_cache_path", "database/openid_consumer_cache" ), self.root )
self.cookie_path = kwargs.get( "cookie_path", "/" )
# web API
self.enable_api = string_as_bool( kwargs.get( 'enable_api', False ) )
+ self.enable_openid = string_as_bool( kwargs.get( 'enable_openid', False ) )
# Communication with a sequencer
self.enable_sequencer_communication = string_as_bool( kwargs.get( 'enable_sequencer_communication', False ) )
# dataset Track files
@@ -161,7 +163,17 @@ class Configuration( object ):
if not os.path.isdir( path ):
raise ConfigurationError("Directory does not exist: %s" % path )
# Create the directories that it makes sense to create
- for path in self.file_path, self.new_file_path, self.job_working_directory, self.cluster_files_directory, self.template_cache, self.ftp_upload_dir, self.library_import_dir, self.user_library_import_dir, self.nginx_upload_store, './static/genetrack/plots', os.path.join( self.tool_data_path, 'shared', 'jars' ):
+ for path in self.file_path, \
+ self.new_file_path, \
+ self.job_working_directory, \
+ self.cluster_files_directory, \
+ self.template_cache, \
+ self.ftp_upload_dir, \
+ self.library_import_dir, \
+ self.user_library_import_dir, \
+ self.nginx_upload_store, \
+ './static/genetrack/plots', \
+ os.path.join( self.tool_data_path, 'shared', 'jars' ):
if path not in [ None, False ] and not os.path.isdir( path ):
try:
os.makedirs( path )
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -1,9 +1,10 @@
"""
Contains the user interface in the Universe class
"""
+from galaxy.web.framework.helpers import time_ago, grids
from galaxy.web.base.controller import *
from galaxy.model.orm import *
-from galaxy import util
+from galaxy import util, model
import logging, os, string, re, smtplib, socket
from random import choice
from email.MIMEText import MIMEText
@@ -26,48 +27,337 @@ require_login_creation_template = requir
VALID_USERNAME_RE = re.compile( "^[a-z0-9\-]+$" )
+OPENID_PROVIDERS = { 'Google' : 'https://www.google.com/accounts/o8/id',
+ 'Yahoo!' : 'http://yahoo.com',
+ 'AOL/AIM' : 'http://openid.aol.com',
+ 'Flickr' : 'http://flickr.com',
+ 'Launchpad' : 'http://login.launchpad.net',
+ }
+
+class UserOpenIDGrid( grids.Grid ):
+ use_panels = False
+ title = "OpenIDs linked to your account"
+ model_class = model.UserOpenID
+ template = '/user/openid_manage.mako'
+ default_filter = { "openid" : "All" }
+ default_sort_key = "-create_time"
+ columns = [
+ grids.TextColumn( "OpenID URL", key="openid" ),
+ grids.GridColumn( "Created", key="create_time", format=time_ago ),
+ ]
+ operations = [
+ grids.GridOperation( "Delete", async_compatible=True ),
+ ]
+ def build_initial_query( self, trans, **kwd ):
+ return trans.sa_session.query( self.model_class ).filter( self.model_class.user_id == trans.user.id )
+
class User( BaseController, UsesFormDefinitionWidgets ):
+ user_openid_grid = UserOpenIDGrid()
@web.expose
def index( self, trans, webapp='galaxy', **kwd ):
return trans.fill_template( '/user/index.mako', webapp=webapp )
@web.expose
+ def openid_auth( self, trans, webapp='galaxy', **kwd ):
+ if not trans.app.config.enable_openid:
+ return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
+ message = 'Unspecified failure authenticating via OpenID'
+ status = kwd.get( 'status', 'done' )
+ openid_url = kwd.get( 'openid_url', '' )
+ openid_provider = kwd.get( 'openid_provider', '' )
+ referer = kwd.get( 'referer', trans.request.referer )
+ auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ action = 'login'
+ if auto_associate:
+ action = 'openid_manage'
+ if not referer:
+ referer = url_for( '/' )
+ consumer = trans.app.openid_manager.get_consumer( trans )
+ process_url = trans.request.base.rstrip( '/' ) + url_for( controller='user', action='openid_process', referer=referer, auto_associate=auto_associate )
+ if not openid_url and openid_provider and openid_provider in OPENID_PROVIDERS:
+ openid_url = OPENID_PROVIDERS[openid_provider]
+ if openid_url:
+ request = None
+ try:
+ request = consumer.begin( openid_url )
+ if request is None:
+ message = 'No OpenID services are available at %s' % openid_url
+ except Exception, e:
+ message = 'Failed to begin OpenID authentication: %s' % str( e )
+ if request is not None:
+ trans.app.openid_manager.add_sreg( trans, request, optional=[ 'nickname', 'email' ] )
+ if request.shouldSendRedirect():
+ redirect_url = request.redirectURL(
+ trans.request.base, process_url )
+ trans.app.openid_manager.persist_session( trans, consumer )
+ trans.response.send_redirect( redirect_url )
+ return
+ else:
+ form = request.htmlMarkup( trans.request.base, process_url, form_tag_attrs={'id':'openid_message','target':'_top'} )
+ trans.app.openid_manager.persist_session( trans, consumer )
+ return form
+ return trans.response.send_redirect( url_for( controller='user',
+ action=action,
+ use_panels=use_panels,
+ message=message,
+ status='error' ) )
+ @web.expose
+ def openid_process( self, trans, webapp='galaxy', **kwd ):
+ if not trans.app.config.enable_openid:
+ return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
+ auto_associate = util.string_as_bool( kwd.get( 'auto_associate', False ) )
+ action = 'login'
+ if auto_associate:
+ action = 'openid_manage'
+ if trans.app.config.bugs_email is not None:
+ contact = '<a href="mailto:%s">contact support</a>' % trans.app.config.bugs_email
+ else:
+ contact = 'contact support'
+ message = 'Verification failed for an unknown reason. Please contact support for assistance.'
+ status = 'error'
+ consumer = trans.app.openid_manager.get_consumer( trans )
+ info = consumer.complete( kwd, trans.request.url )
+ display_identifier = info.getDisplayIdentifier()
+ redirect_url = kwd.get( 'referer', url_for( '/' ) )
+ if info.status == trans.app.openid_manager.FAILURE and display_identifier:
+ message = "Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % ( contact, info.message )
+ return trans.response.send_redirect( url_for( controller='user',
+ action=action,
+ use_panels=True,
+ message=message,
+ status='error' ) )
+ elif info.status == trans.app.openid_manager.SUCCESS:
+ if info.endpoint.canonicalID:
+ display_identifier = info.endpoint.canonicalID
+ user_openid = trans.sa_session.query( trans.app.model.UserOpenID ).filter( trans.app.model.UserOpenID.table.c.openid == display_identifier ).first()
+ if not user_openid:
+ user_openid = trans.app.model.UserOpenID( session=trans.galaxy_session, openid=display_identifier )
+ elif not user_openid.user and user_openid.session.id != trans.galaxy_session.id:
+ user_openid.session = trans.galaxy_session
+ elif user_openid.user and not auto_associate:
+ trans.handle_user_login( user_openid.user, webapp )
+ trans.log_event( "User logged in via OpenID: %s" % display_identifier )
+ trans.response.send_redirect( redirect_url )
+ return
+ if auto_associate and trans.user:
+ # The user is already logged in and requested association from
+ # the user prefs as opposed to using the OpenID form on the
+ # login page.
+ if user_openid.user and user_openid.user.id != trans.user.id:
+ message = "The OpenID <strong>%s</strong> is already associated with another Galaxy account, <strong>%s</strong>. Please disassociate it from that account before attempting to associate it with a new account." % ( display_identifier, user_openid.user.email )
+ status = "error"
+ elif user_openid.user and user_openid.user.id == trans.user.id:
+ message = "The OpenID <strong>%s</strong> is already associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
+ status = "warning"
+ else:
+ user_openid.user_id = trans.user.id
+ trans.sa_session.add( user_openid )
+ trans.sa_session.flush()
+ trans.log_event( "User associated OpenID: %s" % display_identifier )
+ message = "The OpenID <strong>%s</strong> has been associated with your Galaxy account, <strong>%s</strong>." % ( display_identifier, trans.user.email )
+ status = "done"
+ trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=True,
+ message=message,
+ status=status ) )
+ return
+ trans.sa_session.add( user_openid )
+ trans.sa_session.flush()
+ message = "OpenID authentication was successful, but you need to associate your OpenID with a Galaxy account."
+ sreg_resp = trans.app.openid_manager.get_sreg( info )
+ try:
+ username = sreg_resp.get( 'nickname', '' )
+ except AttributeError:
+ username = ''
+ try:
+ email = sreg_resp.get( 'email', '' )
+ except AttributeError:
+ email = ''
+ trans.response.send_redirect( url_for( controller='user',
+ action='openid_associate',
+ use_panels=True,
+ username=username,
+ email=email,
+ message=message,
+ status='warning' ) )
+ elif info.status == trans.app.openid_manager.CANCEL:
+ message = "Login via OpenID was cancelled by an action at the OpenID provider's site."
+ status = "warning"
+ elif info.status == trans.app.openid_manager.SETUP_NEEDED:
+ if info.setup_url:
+ return trans.response.send_redirect( info.setup_url )
+ else:
+ message = "Unable to log in via OpenID. Setup at the provider is required before this OpenID can be used. Please visit your provider's site to complete this step."
+ return trans.response.send_redirect( url_for( controller='user',
+ action=action,
+ use_panels=True,
+ message=message,
+ status=status ) )
+ @web.expose
+ def openid_associate( self, trans, webapp='galaxy', **kwd ):
+ if not trans.app.config.enable_openid:
+ return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ email = kwd.get( 'email', '' )
+ username = kwd.get( 'username', '' )
+ referer = kwd.get( 'referer', trans.request.referer )
+ params = util.Params( kwd )
+ admin_view = util.string_as_bool( params.get( 'admin_view', False ) )
+ openids = trans.galaxy_session.openids
+ if not openids:
+ return trans.show_error_message( 'You have not successfully completed an OpenID authentication in this session. You can do so on the <a href="%s">login</a> page.' % url_for( controller='user', action='login', use_panels=use_panels ) )
+ elif admin_view:
+ return trans.show_error_message( 'Associating OpenIDs with accounts cannot be done by administrators.' )
+ if kwd.get( 'login_button', False ):
+ message, status, user, success = self.__validate_login( trans, webapp, **kwd )
+ if success:
+ for openid in openids:
+ openid.user = user
+ trans.sa_session.add( openid )
+ trans.sa_session.flush()
+ for openid in openids:
+ trans.log_event( "User associated OpenID: %s" % openid.openid )
+ redirect_url = referer
+ if not redirect_url:
+ redirect_url = url_for( '/' )
+ trans.response.send_redirect( redirect_url )
+ return
+ if kwd.get( 'create_user_button', False ):
+ password = kwd.get( 'password', '' )
+ confirm = kwd.get( 'confirm', '' )
+ subscribe = params.get( 'subscribe', '' )
+ subscribe_checked = CheckboxField.is_checked( subscribe )
+ error = ''
+ if not trans.app.config.allow_user_creation and not trans.user_is_admin():
+ error = 'User registration is disabled. Please contact your Galaxy administrator for an account.'
+ else:
+ # Check email and password validity
+ error = self.__validate( trans, params, email, password, confirm, username, webapp )
+ if not error:
+ # all the values are valid
+ message, status, user, success = self.__register( trans, webapp, email, password, username, subscribe_checked, kwd )
+ if success:
+ trans.handle_user_login( user, webapp )
+ trans.log_event( "User created a new account" )
+ trans.log_event( "User logged in" )
+ for openid in openids:
+ openid.user = user
+ trans.sa_session.add( openid )
+ trans.sa_session.flush()
+ for openid in openids:
+ trans.log_event( "User associated OpenID: %s" % openid.openid )
+ redirect_url = referer
+ if not redirect_url:
+ redirect_url = url_for( '/' )
+ trans.response.send_redirect( redirect_url )
+ else:
+ message = error
+ status = 'error'
+ if webapp == 'galaxy':
+ user_info_select, user_info_form, widgets = self.__user_info_ui( trans, **kwd )
+ else:
+ user_info_select = []
+ user_info_form = []
+ widgets = []
+ return trans.fill_template( '/user/openid_associate.mako',
+ webapp=webapp,
+ email=email,
+ password='',
+ confirm='',
+ username=username,
+ header='',
+ use_panels=use_panels,
+ redirect_url='',
+ referer='',
+ refresh_frames=[],
+ message=message,
+ status=status,
+ active_view="user",
+ subscribe_checked=False,
+ admin_view=False,
+ user_info_select=user_info_select,
+ user_info_form=user_info_form,
+ widgets=widgets,
+ openids=openids )
+ @web.expose
+ @web.require_login( 'manage OpenIDs' )
+ def openid_disassociate( self, trans, webapp='galaxy', **kwd ):
+ if not trans.app.config.enable_openid:
+ return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
+ params = util.Params( kwd )
+ ids = params.get( 'id', None )
+ message = params.get( 'message', None )
+ status = params.get( 'status', None )
+ use_panels = params.get( 'use_panels', False )
+ user_openids = []
+ if not ids:
+ message = 'You must select at least one OpenID to disassociate from your Galaxy account.'
+ status = 'error'
+ else:
+ ids = util.listify( params.id )
+ for id in ids:
+ id = trans.security.decode_id( id )
+ user_openid = trans.sa_session.query( trans.app.model.UserOpenID ).get( int( id ) )
+ if not user_openid or ( trans.user.id != user_openid.user_id ):
+ message = 'The selected OpenID(s) are not associated with your Galaxy account.'
+ status = 'error'
+ user_openids = []
+ break
+ user_openids.append( user_openid )
+ if user_openids:
+ deleted_urls = []
+ for user_openid in user_openids:
+ trans.sa_session.delete( user_openid )
+ deleted_urls.append( user_openid.openid )
+ trans.sa_session.flush()
+ for deleted_url in deleted_urls:
+ trans.log_event( "User disassociated OpenID: %s" % deleted_url )
+ message = '%s OpenIDs were disassociated from your Galaxy account.' % len( ids )
+ status = 'done'
+ trans.response.send_redirect( url_for( controller='user',
+ action='openid_manage',
+ use_panels=use_panels,
+ message=message,
+ status=status ) )
+ @web.expose
+ @web.require_login( 'manage OpenIDs' )
+ def openid_manage( self, trans, webapp='galaxy', **kwd ):
+ if not trans.app.config.enable_openid:
+ return trans.show_error_message( 'OpenID authentication is not enabled in this instance of Galaxy' )
+ use_panels = kwd.get( 'use_panels', False )
+ if 'operation' in kwd:
+ operation = kwd['operation'].lower()
+ if operation == "delete":
+ trans.response.send_redirect( url_for( controller='user',
+ action='openid_disassociate',
+ use_panels=use_panels,
+ id=kwd['id'] ) )
+ kwd['referer'] = url_for( controller='user', action='openid_manage', use_panels=True )
+ kwd['openid_providers'] = OPENID_PROVIDERS
+ return self.user_openid_grid( trans, **kwd )
+ @web.expose
def login( self, trans, webapp='galaxy', redirect_url='', refresh_frames=[], **kwd ):
referer = kwd.get( 'referer', trans.request.referer )
- use_panels = util.string_as_bool( kwd.get( 'use_panels', True ) )
+ use_panels = util.string_as_bool( kwd.get( 'use_panels', False ) )
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
header = ''
user = None
email = kwd.get( 'email', '' )
if kwd.get( 'login_button', False ):
- password = kwd.get( 'password', '' )
- referer = kwd.get( 'referer', '' )
if webapp == 'galaxy' and not refresh_frames:
if trans.app.config.require_login:
refresh_frames = [ 'masthead', 'history', 'tools' ]
else:
refresh_frames = [ 'masthead', 'history' ]
- user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first()
- if not user:
- message = "No such user"
- status = 'error'
- elif user.deleted:
- message = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
- status = 'error'
- elif user.external:
- message = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
- status = 'error'
- elif not user.check_password( password ):
- message = "Invalid password"
- status = 'error'
- else:
- trans.handle_user_login( user, webapp )
- trans.log_event( "User logged in" )
- message = 'You are now logged in as %s.<br>You can <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>.' % \
- ( user.email, referer, url_for( '/' ) )
- if trans.app.config.require_login:
- message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( '/static/welcome.html' )
+ message, status, user, success = self.__validate_login( trans, webapp, **kwd )
+ if success and referer:
redirect_url = referer
+ elif success:
+ redirect_url = url_for( '/' )
if not user and trans.app.config.require_login:
if trans.app.config.allow_user_creation:
header = require_login_creation_template % web.url_for( action='create' )
@@ -83,7 +373,37 @@ class User( BaseController, UsesFormDefi
refresh_frames=refresh_frames,
message=message,
status=status,
+ openid_providers=OPENID_PROVIDERS,
active_view="user" )
+ def __validate_login( self, trans, webapp='galaxy', **kwd ):
+ message = kwd.get( 'message', '' )
+ status = kwd.get( 'status', 'done' )
+ email = kwd.get( 'email', '' )
+ password = kwd.get( 'password', '' )
+ referer = kwd.get( 'referer', trans.request.referer )
+ success = False
+ user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first()
+ if not user:
+ message = "No such user"
+ status = 'error'
+ elif user.deleted:
+ message = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
+ status = 'error'
+ elif user.external:
+ message = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
+ status = 'error'
+ elif not user.check_password( password ):
+ message = "Invalid password"
+ status = 'error'
+ else:
+ trans.handle_user_login( user, webapp )
+ trans.log_event( "User logged in" )
+ message = 'You are now logged in as %s.<br>You can <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>.' % \
+ ( user.email, referer, url_for( '/' ) )
+ if trans.app.config.require_login:
+ message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( '/static/welcome.html' )
+ success = True
+ return ( message, status, user, success )
@web.expose
def logout( self, trans, webapp='galaxy' ):
if webapp == 'galaxy':
@@ -138,54 +458,25 @@ class User( BaseController, UsesFormDefi
error = self.__validate( trans, params, email, password, confirm, username, webapp )
if not error:
# all the values are valid
- user = trans.app.model.User( email=email )
- user.set_password_cleartext( password )
- user.username = username
- trans.sa_session.add( user )
- trans.sa_session.flush()
- trans.app.security_agent.create_private_user_role( user )
- message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
- if webapp == 'galaxy':
- # We set default user permissions, before we log in and set the default history permissions
- trans.app.security_agent.user_set_default_permissions( user,
- default_access_private=trans.app.config.new_user_dataset_access_role_default_private )
- # save user info
- self.__save_user_info( trans, user, action='create', new_user=True, **kwd )
- 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."
- else:
- msg = MIMEText( 'Join Mailing list.\n' )
- to = msg[ 'To' ] = trans.app.config.mailing_join_addr
- frm = msg[ 'From' ] = email
- msg[ 'Subject' ] = 'Join Mailing List'
- try:
- s = smtplib.SMTP()
- s.connect( trans.app.config.smtp_server )
- s.sendmail( frm, [ to ], msg.as_string() )
- s.close()
- except:
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
- if not error and not admin_view:
- # 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
- trans.handle_user_login( user, webapp )
- trans.log_event( "User created a new account" )
- trans.log_event( "User logged in" )
- elif not error:
- trans.response.send_redirect( web.url_for( controller='admin',
- action='users',
- message='Created new user account (%s)' % user.email,
- status='done' ) )
- elif not admin_view:
+ message, status, user, success = self.__register( trans, webapp, email, password, username, subscribe_checked, kwd )
+ if success and not admin_view and webapp != 'galaxy':
# Must be logging into the community space webapp
trans.handle_user_login( user, webapp )
- if not error:
- redirect_url = referer
- if error:
- message=error
- status='error'
+ redirect_url = referer
+ if success and not admin_view:
+ # 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
+ trans.handle_user_login( user, webapp )
+ trans.log_event( "User created a new account" )
+ trans.log_event( "User logged in" )
+ elif success:
+ trans.response.send_redirect( web.url_for( controller='admin',
+ action='users',
+ message='Created new user account (%s)' % user.email,
+ status='done' ) )
+ else:
+ message = error
+ status = 'error'
if webapp == 'galaxy':
user_info_select, user_info_form, widgets = self.__user_info_ui( trans, **kwd )
else:
@@ -209,6 +500,57 @@ class User( BaseController, UsesFormDefi
refresh_frames=refresh_frames,
message=message,
status=status )
+ def __register( self, trans, webapp, email, password, username, subscribe_checked, kwd ):
+ status = kwd.get( 'status', 'done' )
+ admin_view = util.string_as_bool( kwd.get( 'admin_view', False ) )
+ user = trans.app.model.User( email=email )
+ user.set_password_cleartext( password )
+ user.username = username
+ trans.sa_session.add( user )
+ trans.sa_session.flush()
+ trans.app.security_agent.create_private_user_role( user )
+ error = ''
+ if webapp == 'galaxy':
+ # We set default user permissions, before we log in and set the default history permissions
+ trans.app.security_agent.user_set_default_permissions( user,
+ default_access_private=trans.app.config.new_user_dataset_access_role_default_private )
+ # save user info
+ self.__save_user_info( trans, user, action='create', new_user=True, **kwd )
+ 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."
+ else:
+ msg = MIMEText( 'Join Mailing list.\n' )
+ to = msg[ 'To' ] = trans.app.config.mailing_join_addr
+ frm = msg[ 'From' ] = email
+ msg[ 'Subject' ] = 'Join Mailing List'
+ try:
+ s = smtplib.SMTP()
+ s.connect( trans.app.config.smtp_server )
+ s.sendmail( frm, [ to ], msg.as_string() )
+ s.close()
+ except:
+ error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
+ if not error and not admin_view:
+ # 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
+ trans.handle_user_login( user, webapp )
+ trans.log_event( "User created a new account" )
+ trans.log_event( "User logged in" )
+ elif not error:
+ trans.response.send_redirect( web.url_for( controller='admin',
+ action='users',
+ message='Created new user account (%s)' % user.email,
+ status='done' ) )
+ if error:
+ message = error
+ status = 'error'
+ success = False
+ else:
+ message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
+ success = True
+ return ( message, status, user, success )
def __save_user_info(self, trans, user, action, new_user=True, **kwd):
'''
This method saves the user information for new users as well as editing user
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -29,12 +29,19 @@
##
<%def name="center_panel()">
- ${make_grid( grid )}
+ ${self.grid_body( grid )}
</%def>
## Render the grid's basic elements. Each of these elements can be subclassed.
<%def name="body()">
- ${make_grid( grid )}
+ ${self.grid_body( grid )}
+</%def>
+
+## Because body() is special and always exists even if not explicitly defined,
+## it's not possible to override body() in the topmost template in the chain.
+## Because of this, override grid_body() instead.
+<%def name="grid_body( grid )">
+ ${self.make_grid( grid )}
</%def><%def name="title()">${grid.title}</%def>
1
0
galaxy-dist commit 5a217a7ce999: Replaced request with 'sequencing request' in sample tracking ui.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1289922517 18000
# Node ID 5a217a7ce999bbe218432a7442751b5b78684798
# Parent 33dacaafc62eac4a8940c4bc978da1d1a6c68af9
Replaced request with 'sequencing request' in sample tracking ui.
Show the request page instead of the request grid after submitting the request
--- a/templates/admin/requests/edit_request_type.mako
+++ b/templates/admin/requests/edit_request_type.mako
@@ -28,7 +28,7 @@
</div><div class="form-row"><label>
- Request Form definition:
+ Sequencing Request Form definition:
</label><select name="form_id">
%for form in forms:
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -69,16 +69,16 @@
</div></ul>
-%if request.samples_without_library_destinations:
+%if request.is_rejected:
<p>
- <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font>
+ <font color="red"><b>${request.last_comment}</b></font></p>
%endif
-%if request.is_rejected:
- <br/>
- <font color="red"><b><i>Reason for rejection: </i></b></font><b>${request.last_comment}</b>
- <br/>
+%if request.samples_without_library_destinations:
+ <p>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font>
+ </p>
%endif
%if message:
@@ -90,9 +90,9 @@
%if displayable_sample_widgets:
<%
if editing_samples:
- grid_header = '<h3>Edit Current Samples of Request "%s"</h3>' % request.name
+ grid_header = '<h3>Edit Current Samples of Sequencing Request "%s"</h3>' % request.name
else:
- grid_header = '<h3>Add Samples to Request "%s"</h3>' % request.name
+ grid_header = '<h3>Add Samples to Sequencing Request "%s"</h3>' % request.name
%>
${render_samples_grid( cntrller, request, displayable_sample_widgets, action='edit_samples', editing_samples=editing_samples, encoded_selected_sample_ids=encoded_selected_sample_ids, render_buttons=False, grid_header=grid_header )}
%if editing_samples and len( sample_operation_select_field.options ) > 1 and not is_unsubmitted:
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -157,7 +157,7 @@ class RequestsCommon( BaseController, Us
status = 'error'
else:
request = self.__save_request( trans, cntrller, **kwd )
- message = 'The request has been created.'
+ message = 'The sequencing request has been created.'
if params.get( 'create_request_button', False ):
return trans.response.send_redirect( web.url_for( controller=cntrller,
action='browse_requests',
@@ -316,7 +316,7 @@ class RequestsCommon( BaseController, Us
trans.sa_session.flush()
trans.sa_session.refresh( request )
# Create an event with state 'New' for this new request
- comment = "Request created by %s" % trans.user.email
+ comment = "Sequencing request created by %s" % trans.user.email
if request.user != trans.user:
comment += " on behalf of %s." % request.user.email
event = trans.model.RequestEvent( request, request.states.NEW, comment )
@@ -358,7 +358,7 @@ class RequestsCommon( BaseController, Us
status='error',
message=message ) )
# Change the request state to 'Submitted'
- comment = "Request submitted by %s" % trans.user.email
+ comment = "Sequencing request submitted by %s" % trans.user.email
if request.user != trans.user:
comment += " on behalf of %s." % request.user.email
event = trans.model.RequestEvent( request, request.states.SUBMITTED, comment )
@@ -373,7 +373,7 @@ class RequestsCommon( BaseController, Us
# request's RequestType configured by the admin.
initial_sample_state_after_request_submitted = request.type.states[0]
for sample in request.samples:
- event_comment = 'Request submitted and sample state set to %s.' % request.type.states[0].name
+ event_comment = 'Sequencing request submitted and sample state set to %s.' % request.type.states[0].name
event = trans.model.SampleEvent( sample,
initial_sample_state_after_request_submitted,
event_comment )
@@ -381,9 +381,10 @@ class RequestsCommon( BaseController, Us
trans.sa_session.add( request )
trans.sa_session.flush()
request.send_email_notification( trans, initial_sample_state_after_request_submitted )
- message = 'The request has been submitted.'
- return trans.response.send_redirect( web.url_for( controller=cntrller,
- action='browse_requests',
+ message = 'The sequencing request has been submitted.'
+ # show the request page after submitting the request
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ action='view_request',
cntrller=cntrller,
id=request_id,
status=status,
@@ -528,7 +529,7 @@ class RequestsCommon( BaseController, Us
for s in request.samples:
s.deleted = True
trans.sa_session.add( s )
- comment = "Request marked deleted by %s." % trans.user.email
+ comment = "Sequencing request marked deleted by %s." % trans.user.email
# There is no DELETED state for a request, so keep the current request state
event = trans.model.RequestEvent( request, request.state, comment )
trans.sa_session.add( event )
@@ -568,7 +569,7 @@ class RequestsCommon( BaseController, Us
for s in request.samples:
s.deleted = False
trans.sa_session.add( s )
- comment = "Request marked undeleted by %s." % trans.user.email
+ comment = "Sequencing request marked undeleted by %s." % trans.user.email
event = trans.model.RequestEvent( request, request.state, comment )
trans.sa_session.add( event )
trans.sa_session.flush()
@@ -686,11 +687,11 @@ class RequestsCommon( BaseController, Us
request_type_state = request.type.final_sample_state
if common_state.id == request_type_state.id:
# since all the samples are in the final state, change the request state to 'Complete'
- comment = "All samples of this request are in the final sample state (%s). " % request_type_state.name
+ comment = "All samples of this sequencing request are in the final sample state (%s). " % request_type_state.name
state = request.states.COMPLETE
final_state = True
else:
- comment = "All samples of this request are in the (%s) sample state. " % common_state.name
+ comment = "All samples of this sequencing request are in the (%s) sample state. " % common_state.name
state = request.states.SUBMITTED
event = trans.model.RequestEvent( request, state, comment )
trans.sa_session.add( event )
--- a/templates/admin/requests/view_request_type.mako
+++ b/templates/admin/requests/view_request_type.mako
@@ -38,7 +38,7 @@
<div style="clear: both"></div></div><div class="form-row">
- <label>Request form definition</label>
+ <label>Sequencing Request form definition</label>
${request_type.request_form.name}
</div><div class="form-row">
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -223,11 +223,11 @@ class RequestsAdmin( BaseController, Use
status=status,
message=message )
# Create an event with state 'Rejected' for this request
- event_comment = "Request marked rejected by %s. Reason: %s " % ( trans.user.email, comment )
+ event_comment = "Sequencing request marked rejected by %s. Reason: %s " % ( trans.user.email, comment )
event = trans.model.RequestEvent( request, request.states.REJECTED, event_comment )
trans.sa_session.add( event )
trans.sa_session.flush()
- message='Request (%s) has been rejected.' % request.name
+ message='Sequencing request (%s) has been rejected.' % request.name
return trans.response.send_redirect( web.url_for( controller='requests_admin',
action='browse_requests',
status=status,
--- a/templates/admin/requests/reject.mako
+++ b/templates/admin/requests/reject.mako
@@ -5,7 +5,6 @@
${render_msg( message, status )}
%endif
<br/><br/>
-##<h2>Reject Sequencing Request "${request.name}"</h2><ul class="manage-table-actions"><li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">View history</a>
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -52,14 +52,14 @@
</ul>
%if request.is_rejected:
- <br/>
- <font color="red"><b><i>Reason for rejection: </i></b></font><b>${request.last_comment}</b>
- <br/>
+ <p>
+ <font color="red"><b>${request.last_comment}</b></font>
+ </p>
%endif
%if request.samples_without_library_destinations:
<p>
- <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font></p>
%endif
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -159,6 +159,8 @@
<input type="hidden" name="sample_${sample_widget_index}_bar_code" value="${sample_widget['bar_code']}"/>
%endif
</td>
+ %else:
+ <td></td>
%endif
%if sample:
%if is_unsubmitted:
1
0
galaxy-dist commit 02f6c9dae26e: Data libraries: Fix 'import from current history' showing metadata files that are not visible. Also fix this same issue for 'Copy history items' feature. Do this by adding new 'visible_datasets' mapping property for HDAs. Checkbox labels for both features can now be clicked.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1289852143 18000
# Node ID 02f6c9dae26e9aef40a44bc151ed07b457715839
# Parent 0505090dbbe610741cacd7a9a1c2e79b8cc9ea5c
Data libraries: Fix 'import from current history' showing metadata files that are not visible. Also fix this same issue for 'Copy history items' feature. Do this by adding new 'visible_datasets' mapping property for HDAs. Checkbox labels for both features can now be clicked.
--- a/templates/root/index.mako
+++ b/templates/root/index.mako
@@ -40,7 +40,7 @@
"Show Hidden Datasets": function() {
galaxy_history.location = "${h.url_for( controller='root', action='history', show_hidden=True)}";
},
- "Show structure": function() {
+ "Show Structure": function() {
galaxy_main.location = "${h.url_for( controller='history', action='display_structured' )}";
},
"Export to File": function() {
--- a/templates/library/common/common.mako
+++ b/templates/library/common/common.mako
@@ -427,14 +427,11 @@
<input type="hidden" name="upload_option" value="import_from_history"/><input type="hidden" name="ldda_message" value="${ldda_message}"/><%
+ role_ids_selected = ''
if roles_select_list:
- role_ids_selected = roles_select_list.get_selected( return_value=True, multi=True )
- if role_ids_selected:
- role_ids_selected = ','.join( role_ids_selected )
- else:
- role_ids_selected = ''
- else:
- role_ids_selected = ''
+ selected = roles_select_list.get_selected( return_value=True, multi=True )
+ if selected:
+ role_ids_selected = ','.join( selected )
%><input type="hidden" name="roles" value="${role_ids_selected}"/>
%if replace_dataset not in [ None, 'None' ]:
@@ -450,9 +447,11 @@
${render_template_field( field, render_as_hidden=True )}
%endfor
%endif
- %for hda in history.active_datasets:
+ %for hda in history.visible_datasets:
+ <% encoded_id = trans.security.encode_id( hda.id ) %><div class="form-row">
- <input name="hda_ids" value="${trans.security.encode_id( hda.id )}" type="checkbox"/>${hda.hid}: ${hda.name}
+ <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}: ${hda.name}</label></div>
%endfor
<div class="form-row">
@@ -460,9 +459,7 @@
</div></form>
%else:
- <p/>
- Your current history is empty
- <p/>
+ <p>Your current history is empty</p>
%endif
</div></div>
--- a/templates/dataset/copy_view.mako
+++ b/templates/dataset/copy_view.mako
@@ -17,22 +17,29 @@
</p>
%endif
<p>
+ <div class="infomessage">Select any number of source history items and any number of target histories and click "Copy History Items" to add a copy of each selected history item to each selected target history.</div>
+ <div style="clear: both"></div>
+</p>
+<p><div class="toolForm"><form>
- <div style="float: left; width: 50%; padding: 0px 0px 0px 0px;">
+ <div style="float: left; width: 50%; padding: 0px;"><div class="toolFormTitle">Source History Items</div><div class="toolFormBody">
%for data in source_datasets:
<%
checked = ""
if data.id in source_dataset_ids:
- checked = " checked"
+ checked = " checked='checked'"
%>
- <div class="form-row"><input type="checkbox" name="source_dataset_ids" value="${data.id}"${checked}/> ${data.hid}: ${data.name}</div>
+ <div class="form-row">
+ <input type="checkbox" name="source_dataset_ids" id="dataset_${data.id}" value="${data.id}"${checked}/>
+ <label for="dataset_${data.id}" style="display: inline;font-weight:normal;"> ${data.hid}: ${data.name}</label>
+ </div>
%endfor
</div></div>
- <div style="float: right; width: 50%; padding: 0px 0px 0px 0px;">
+ <div style="float: right; width: 50%; padding: 0px;"><div class="toolFormTitle">Target Histories</div><div class="toolFormBody">
%for i, hist in enumerate( target_histories ):
@@ -44,13 +51,16 @@
if hist == trans.get_history():
cur_history_text = " <strong>(current history)</strong>"
%>
- <div class="form-row"><input type="checkbox" name="target_history_ids" value="${hist.id}"${checked}/> ${i + 1}${cur_history_text}: ${hist.name}</div>
+ <div class="form-row">
+ <input type="checkbox" name="target_history_ids" id="hist_${hist.id}" value="${hist.id}"${checked}/>
+ <label for="hist_${hist.id}" style="display: inline;font-weight:normal;">${i + 1}: ${hist.name}${cur_history_text}</label>
+ </div>
%endfor
%if trans.get_user():
<%
checked = ""
if "create_new_history" in target_history_ids:
- checked = " checked"
+ checked = " checked='checked'"
%><br/><div class="form-row"><input type="checkbox" name="target_history_ids" value="create_new_history"${checked}/>New history named: <input type="textbox" name="new_history_name" value="${new_history_name}"/></div>
@@ -64,8 +74,3 @@
</form></div></p>
-<div style="clear: both"></div>
-<p>
- <div class="infomessage">Select any number of source history items and any number of target histories and click "Copy History Items" to add a copy of each selected history item to each selected target history.</div>
- <div style="clear: both"></div>
-</p>
--- a/lib/galaxy/web/controllers/dataset.py
+++ b/lib/galaxy/web/controllers/dataset.py
@@ -773,7 +773,7 @@ class DatasetInterface( BaseController,
trans.sa_session.refresh( history )
elif create_new_history:
target_history_ids.append( "create_new_history" )
- source_datasets = history.active_datasets
+ source_datasets = history.visible_datasets
target_histories = [history]
if user:
target_histories = user.active_histories
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -1033,7 +1033,9 @@ assign_mapper( context, ImplicitlyConver
assign_mapper( context, History, History.table,
properties=dict( galaxy_sessions=relation( GalaxySessionToHistoryAssociation ),
datasets=relation( HistoryDatasetAssociation, backref="history", order_by=asc(HistoryDatasetAssociation.table.c.hid) ),
- active_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & ( not_( HistoryDatasetAssociation.table.c.deleted ) ) ), order_by=asc( HistoryDatasetAssociation.table.c.hid ), viewonly=True ),
+ active_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & not_( HistoryDatasetAssociation.table.c.deleted ) ), order_by=asc( HistoryDatasetAssociation.table.c.hid ), viewonly=True ),
+ visible_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & not_( HistoryDatasetAssociation.table.c.deleted ) & HistoryDatasetAssociation.table.c.visible ),
+ order_by=asc( HistoryDatasetAssociation.table.c.hid ), viewonly=True ),
tags=relation( HistoryTagAssociation, order_by=HistoryTagAssociation.table.c.id, backref="histories" ),
annotations=relation( HistoryAnnotationAssociation, order_by=HistoryAnnotationAssociation.table.c.id, backref="histories" ),
ratings=relation( HistoryRatingAssociation, order_by=HistoryRatingAssociation.table.c.id, backref="histories" ) )
1
0
galaxy-dist commit 94c2040e5825: More minor ui fixes in sample tracking
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1289918776 18000
# Node ID 94c2040e58255136741d776de8401cfb4128133b
# Parent 7cc69601ca2da9b6d21f980585b59d73c0133cba
More minor ui fixes in sample tracking
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -220,7 +220,7 @@
%endif
%if can_delete_samples:
## Delete button
- <td valign="top"><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=sample_widget_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
+ <td valign="top"><a class="action-button" confirm="This sample is not recoverable after deletion. Click Ok to delete." href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=sample_widget_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
%endif
</%def>
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -12,19 +12,22 @@
<%def name="javascripts()">
${parent.javascripts()}
${common_javascripts()}
+ ${local_javascripts()}
</%def>
-<script type="text/javascript">
- // This function stops the form from getting submitted when return key is pressed
- // This is needed in this form as the barcode scanner (when in keyboard emulation mode)
- // may send a return key appended to the scanned barcode string.
- function stopRKey(evt) {
- var evt = (evt) ? evt : ((event) ? event : null);
- var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
- if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
- }
- document.onkeypress = stopRKey
-</script>
+<%def name="local_javascripts()">
+ <script type="text/javascript">
+ // This function stops the form from getting submitted when return key is pressed
+ // This is needed in this form as the barcode scanner (when in keyboard emulation mode)
+ // may send a return key appended to the scanned barcode string.
+ function stopRKey(evt) {
+ var evt = (evt) ? evt : ((event) ? event : null);
+ var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
+ if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
+ }
+ document.onkeypress = stopRKey
+ </script>
+</%def><%
from galaxy.web.framework.helpers import time_ago
@@ -68,7 +71,7 @@
%if request.samples_without_library_destinations:
<p>
- <font color="red"><b><i>Select a target data library and folder for a sample before selecting its datasets to transfer from the sequencer</i></b></font>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font></p>
%endif
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -59,7 +59,7 @@
%if request.samples_without_library_destinations:
<p>
- <font color="red"><b><i>Select a target data library and folder for a sample before selecting its datasets to transfer from the sequencer</i></b></font>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting it's datasets to transfer from the sequencer</i></b></font></p>
%endif
1
0
galaxy-dist commit d2d0c199c20d: Improvements to annotation display when running workflows: (1) workflow annotation is shown at the top of the page; (2) step annotations are shown in the step header rather than at the bottom. Fixes Issue #420
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User jeremy goecks <jeremy.goecks(a)emory.edu>
# Date 1289925819 18000
# Node ID d2d0c199c20ddf942e1e2587dc9aede8acd9cebc
# Parent 5a217a7ce999bbe218432a7442751b5b78684798
Improvements to annotation display when running workflows: (1) workflow annotation is shown at the top of the page; (2) step annotations are shown in the step header rather than at the bottom. Fixes Issue #420
--- a/lib/galaxy/web/controllers/workflow.py
+++ b/lib/galaxy/web/controllers/workflow.py
@@ -1333,6 +1333,7 @@ class WorkflowController( BaseController
# Connections by input name
step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
# Render the form
+ stored.annotation = self.get_item_annotation_str( trans.sa_session, trans.user, stored )
return trans.fill_template(
"workflow/run.mako",
steps=workflow.steps,
--- a/templates/workflow/run.mako
+++ b/templates/workflow/run.mako
@@ -20,6 +20,14 @@
margin-top: 10px;
margin-bottom: 10px;
}
+ .step-annotation {
+ margin-top: 0.25em;
+ font-weight: normal;
+ font-size: 97%;
+ }
+ .workflow-annotation {
+ margin-bottom: 1em;
+ }
</style></%def>
@@ -129,6 +137,11 @@ from galaxy.jobs.actions.post import Act
</div>
%endif
+%if workflow.annotation:
+ <div class="workflow-annotation">Annotation: ${workflow.annotation}</div>
+ <hr/>
+%endif
+
<form id="tool_form" name="tool_form" method="POST">
## <input type="hidden" name="workflow_name" value="${h.to_unicode( workflow.name ) | h}" />
%for i, step in enumerate( steps ):
@@ -136,7 +149,12 @@ from galaxy.jobs.actions.post import Act
<% tool = app.toolbox.tools_by_id[step.tool_id] %><input type="hidden" name="${step.id}|tool_state" value="${step.state.encode( tool, app )}"><div class="toolForm">
- <div class="toolFormTitle">Step ${int(step.order_index)+1}: ${tool.name}</div>
+ <div class="toolFormTitle">
+ Step ${int(step.order_index)+1}: ${tool.name}
+ % if step.annotations:
+ <div class="step-annotation">Annotation: ${h.to_unicode( step.annotations[0].annotation )}</div>
+ % endif
+ </div><div class="toolFormBody">
${do_inputs( tool.inputs, step.state.inputs, errors.get( step.id, dict() ), "", step )}
% if step.post_job_actions:
@@ -150,27 +168,21 @@ from galaxy.jobs.actions.post import Act
${'<br/>'.join([ActionBox.get_short_str(pja) for pja in step.post_job_actions])}
</div>
% endif
- % if step.annotations:
- <hr/>
- <div class='form-row'>
- <label>Annotation:</label> ${h.to_unicode( step.annotations[0].annotation )}
- </div>
- % endif
</div></div>
%else:
<% module = step.module %><input type="hidden" name="${step.id}|tool_state" value="${module.encode_runtime_state( t, step.state )}"><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}
+ % if step.annotations:
+ <div class="step-annotation">Annotation: ${step.annotations[0].annotation}</div>
+ % endif
+
+ </div><div class="toolFormBody">
${do_inputs( module.get_runtime_inputs(), step.state.inputs, errors.get( step.id, dict() ), "", step )}
- % if step.annotations:
- <hr/>
- <div class='form-row'>
- <label>Annotation:</label> ${step.annotations[0].annotation}
- </div>
- % endif
</div></div>
%endif
1
0
galaxy-dist commit 7cc69601ca2d: minor ui fixes in sample tracking
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1289916735 18000
# Node ID 7cc69601ca2da9b6d21f980585b59d73c0133cba
# Parent def13f052a4a22c46ec5be6481ad874ceb734799
minor ui fixes in sample tracking
--- a/templates/admin/requests/reject.mako
+++ b/templates/admin/requests/reject.mako
@@ -4,8 +4,8 @@
%if message:
${render_msg( message, status )}
%endif
-
-<h2>Reject Sequencing Request "${request.name}"</h2>
+<br/><br/>
+##<h2>Reject Sequencing Request "${request.name}"</h2><ul class="manage-table-actions"><li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">View history</a>
@@ -16,7 +16,7 @@
</ul><div class="toolForm">
- <div class="toolFormTitle">Reject request</div>
+ <div class="toolFormTitle">Reject sequencing request "${request.name}"</div><form name="event" action="${h.url_for( controller='requests_admin', action='reject_request', id=trans.security.encode_id( request.id ) )}" method="post" ><div class="form-row">
Rejecting this request will move the request state to <b>Rejected</b>.
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -58,9 +58,9 @@
%endif
%if request.samples_without_library_destinations:
- <br/>
- <font color="red"><b><i>Select a target data library and folder for all samples before starting the sequence run</i></b></font>
- <br/>
+ <p>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting its datasets to transfer from the sequencer</i></b></font>
+ </p>
%endif
%if message:
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -67,9 +67,9 @@
</ul>
%if request.samples_without_library_destinations:
- <br/>
- <font color="red"><b><i>Select a target data library and folder for all samples before starting the sequence run</i></b></font>
- <br/>
+ <p>
+ <font color="red"><b><i>Select a target data library and folder for a sample before selecting its datasets to transfer from the sequencer</i></b></font>
+ </p>
%endif
%if request.is_rejected:
--- a/templates/requests/common/view_request_history.mako
+++ b/templates/requests/common/view_request_history.mako
@@ -34,7 +34,7 @@
${render_msg( message, status )}
%endif
-<h2>History of sequencing request "${request.name}"</h2>
+<h3>History of sequencing request "${request.name}"</h3><div class="toolForm"><table class="grid">
1
0