diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index c4b8bc67f72..3bf8e27d0b8 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -1629,6 +1629,7 @@ All samples in state: %(sample_state)s event = trans.app.model.RequestEvent(self, self.state(), comments) trans.sa_session.add(event) trans.sa_session.flush() + return comments class RequestEvent( object ): def __init__(self, request=None, request_state=None, comment=''): @@ -1651,6 +1652,28 @@ class RequestType( object ): self.datatx_info = datatx_info def last_state(self): return self.states[-1] + + def change_state_widgets(self, trans, sample=None): + if sample: + curr_state = sample.current_state() + else: + curr_state = self.states[0] + states_input = SelectField('select_state') + for state in self.states: + if curr_state.name == state.name: + states_input.add_option(state.name, state.id, selected=True) + else: + states_input.add_option(state.name, state.id) + widgets = [] + if sample: + widgets.append(('Select the new state of the sample from the list of possible state(s)', + states_input)) + else: + widgets.append(('Select the new state of the selected sample(s) from the list of possible state(s)', + states_input)) + widgets.append(('Comments', TextArea('comment'))) + title = 'Change current state' + return widgets, title class RequestTypePermissions( object ): def __init__( self, action, request_type, role ): @@ -1659,6 +1682,8 @@ class RequestTypePermissions( object ): self.role = role class Sample( object ): + bulk_operations = Bunch(CHANGE_STATE = 'Change state', + SELECT_LIBRARY = 'Select data library and folder') transfer_status = Bunch( NOT_STARTED = 'Not started', IN_QUEUE = 'In queue', TRANSFERRING = 'Transferring dataset', diff --git a/lib/galaxy/web/controllers/requests_admin.py b/lib/galaxy/web/controllers/requests_admin.py index ab6473ded16..1d0b848f021 100644 --- a/lib/galaxy/web/controllers/requests_admin.py +++ b/lib/galaxy/web/controllers/requests_admin.py @@ -321,8 +321,6 @@ class RequestsAdmin( BaseController, UsesFormDefinitionWidgets ): return self.__reject_request( trans, **kwd ) elif operation == "view_type": return self.__view_request_type( trans, **kwd ) - elif operation == "upload_datasets": - return self.__upload_datasets( trans, **kwd ) # Render the grid view return self.request_grid( trans, **kwd ) @@ -399,191 +397,6 @@ class RequestsAdmin( BaseController, UsesFormDefinitionWidgets ): action='list', status='done', message='Request %s has been rejected.' % request.name) ) - - def __upload_datasets(self, trans, **kwd): - return trans.fill_template( '/admin/requests/upload_datasets.mako' ) - - - @web.expose - @web.require_admin - def bar_codes(self, trans, **kwd): - params = util.Params( kwd ) - message = util.restore_text( params.get( 'message', '' ) ) - status = params.get( 'status', 'done' ) - request_id = params.get( 'request_id', None ) - if request_id: - request = trans.sa_session.query( trans.app.model.Request ).get( int( request_id )) - if not request: - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='list', - status='error', - message="Invalid request ID", - **kwd) ) - widgets = [] - for index, sample in enumerate(request.samples): - if sample.bar_code: - bc = sample.bar_code - else: - bc = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - widgets.append(TextField('sample_%i_bar_code' % index, - 40, - bc)) - return trans.fill_template( '/admin/samples/bar_codes.mako', - samples_list=[s for s in request.samples], - user=request.user, request=request, widgets=widgets, - status=status, - message=message) - @web.expose - @web.require_admin - def save_bar_codes(self, trans, **kwd): - params = util.Params( kwd ) - try: - request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', None ) ) ) - except: - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='list', - status='error', - message="Invalid request ID", - **kwd) ) - # validate - # bar codes need to be globally unique - message = '' - for index in range(len(request.samples)): - bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - # check for empty bar code - if not bar_code.strip(): - message = 'Please fill the barcode for sample %s.' % request.samples[index].name - break - # check all the unsaved bar codes - count = 0 - for i in range(len(request.samples)): - if bar_code == util.restore_text(params.get('sample_%i_bar_code' % i, '')): - count = count + 1 - if count > 1: - message = '''The barcode %s of sample %s belongs - another sample in this request. The sample barcodes must - be unique throughout the system''' % \ - (bar_code, request.samples[index].name) - break - # check all the saved bar codes - all_samples = trans.sa_session.query( trans.app.model.Sample ) - for sample in all_samples: - if bar_code == sample.bar_code: - message = '''The bar code %s of sample %s - belongs another sample. The sample bar codes must be - unique throughout the system''' % \ - (bar_code, request.samples[index].name) - break - if message: - break - if message: - widgets = [] - for index, sample in enumerate(request.samples): - if sample.bar_code: - bc = sample.bar_code - else: - bc = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - widgets.append(TextField('sample_%i_bar_code' % index, - 40, - util.restore_text(params.get('sample_%i_bar_code' % index, '')))) - return trans.fill_template( '/admin/samples/bar_codes.mako', - samples_list=[s for s in request.samples], - user=request.user, request=request, widgets=widgets, status='error', - message=message) - # now save the bar codes - for index, sample in enumerate(request.samples): - bar_code = util.restore_text(params.get('sample_%i_bar_code' % index, '')) - sample.bar_code = bar_code - trans.sa_session.add( sample ) - trans.sa_session.flush() - # change the state of all the samples to the next state - # get the new state - new_state = request.type.states[1] - for s in request.samples: - event = trans.app.model.SampleEvent(s, new_state, 'Bar code added to this sample') - trans.sa_session.add( event ) - trans.sa_session.flush() - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='list', - operation='show_request', - id=trans.security.encode_id(request.id), - message='Bar codes have been saved for this request', - status='done')) - @web.expose - @web.require_admin - def update_request_state( self, trans, **kwd ): - params = util.Params( kwd ) - try: - request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', None ) ) ) - sample_id = int(params.get('sample_id', False)) - except: - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='list', - status='error', - message="Invalid request ID", - **kwd) ) - # check if all the samples of the current request are in the sample state - common_state = request.common_state() - if not common_state: - # if the current request state is complete and one of its samples moved from - # the final sample state, then move the request state to In-progress - if request.complete(): - event = trans.app.model.RequestEvent(request, request.states.SUBMITTED, "One or more samples' state moved from the final sample state.") - trans.sa_session.add( event ) - trans.sa_session.flush() - return trans.response.send_redirect( web.url_for( controller='requests_common', - cntrller='requests_admin', - action='sample_events', - sample_id=sample_id)) - final_state = False - if common_state.id == request.type.last_state().id: - # since all the samples are in the final state, change the request state to 'Complete' - comments = "All samples of this request are in the last sample state (%s)." % request.type.last_state().name - state = request.states.COMPLETE - final_state = True - else: - comments = "All samples are in %s state." % common_state.name - state = request.states.SUBMITTED - event = trans.app.model.RequestEvent(request, state, comments) - trans.sa_session.add( event ) - trans.sa_session.flush() - # check if an email notification is configured to be sent when the samples - # are in this state -# if common_state.id in request.notification['sample_states']: - request.send_email_notification(trans, common_state, final_state) - return trans.response.send_redirect( web.url_for( controller='requests_common', - cntrller='requests_admin', - action='sample_events', - sample_id=sample_id)) - - @web.expose - @web.require_admin - def save_state(self, trans, **kwd): - params = util.Params( kwd ) - try: - sample_id = int(params.get('sample_id', False)) - sample = trans.sa_session.query( trans.app.model.Sample ).get( sample_id ) - except: - message = "Invalid sample ID" - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='list', - status='error', - message=message, - **kwd) ) - comments = util.restore_text( params.comment ) - selected_state = int( params.select_state ) - new_state = trans.sa_session.query( trans.app.model.SampleState ) \ - .filter( and_( trans.app.model.SampleState.table.c.request_type_id == sample.request.type.id, - trans.app.model.SampleState.table.c.id == selected_state ) ) \ - .first() - event = trans.app.model.SampleEvent(sample, new_state, comments) - trans.sa_session.add( event ) - trans.sa_session.flush() - return trans.response.send_redirect( web.url_for( controller='requests_admin', - cntrller='requests_admin', - action='update_request_state', - request_id=sample.request.id, - sample_id=sample.id)) # # Data transfer from sequencer # diff --git a/lib/galaxy/web/controllers/requests_common.py b/lib/galaxy/web/controllers/requests_common.py index ae94e801fed..2be1a6fded0 100644 --- a/lib/galaxy/web/controllers/requests_common.py +++ b/lib/galaxy/web/controllers/requests_common.py @@ -515,7 +515,7 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): @web.require_login( "create/submit sequencing requests" ) def events(self, trans, **kwd): params = util.Params( kwd ) - cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) ) + cntrller = params.get( 'cntrller', 'requests' ) try: request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) ) except: @@ -533,21 +533,63 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): cntrller=cntrller, events_list=events_list, request=request) @web.expose - @web.require_login( "create/submit sequencing requests" ) - def settings(self, trans, **kwd): + @web.require_admin + def update_request_state( self, trans, **kwd ): params = util.Params( kwd ) - message = util.restore_text( params.get( 'message', '' ) ) cntrller = params.get( 'cntrller', 'requests' ) try: - request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) ) + request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', None ) ) ) except: - return trans.response.send_redirect( web.url_for( controller=cntrller, + return trans.response.send_redirect( web.url_for( controller='requests_admin', action='list', status='error', - message="Invalid request ID") ) - return trans.fill_template( '/requests/common/settings.mako', - cntrller=cntrller, request=request) - + message="Invalid request ID", + **kwd) ) + # check if all the samples of the current request are in the sample state + common_state = request.common_state() + if not common_state: + # if the current request state is complete and one of its samples moved from + # the final sample state, then move the request state to In-progress + if request.complete(): + status='done' + message = "One or more samples' state moved from the final sample state. Now request in '%s' state" % request.states.SUBMITTED + event = trans.app.model.RequestEvent(request, request.states.SUBMITTED, message) + trans.sa_session.add( event ) + trans.sa_session.flush() + else: + message = '' + status = 'ok' + return trans.response.send_redirect( web.url_for( controller=cntrller, + action='list', + operation='show', + id=trans.security.encode_id(request.id), + status=status, + message=message ) ) + final_state = False + if common_state.id == request.type.last_state().id: + # since all the samples are in the final state, change the request state to 'Complete' + comments = "All samples of this request are in the last sample state (%s). " % request.type.last_state().name + state = request.states.COMPLETE + final_state = True + else: + comments = "All samples are in %s state. " % common_state.name + state = request.states.SUBMITTED + event = trans.app.model.RequestEvent(request, state, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() + # check if an email notification is configured to be sent when the samples + # are in this state + retval = request.send_email_notification(trans, common_state, final_state) + if retval: + message = comments + retval + else: + message = comments + return trans.response.send_redirect( web.url_for( controller=cntrller, + action='list', + operation='show', + id=trans.security.encode_id(request.id), + status='done', + message=message ) ) @web.expose @web.require_login( "create/submit sequencing requests" ) def show(self, trans, **kwd): @@ -588,9 +630,10 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): folder_widget=folder_widget)) return trans.fill_template( '/requests/common/show_request.mako', cntrller=cntrller, - request=request, + request=request, selected_samples=[], request_details=self.request_details(trans, request.id), current_samples=current_samples, + sample_ops=self.__sample_operation_selectbox(trans, request, **kwd), sample_copy=self.__copy_sample(current_samples), details='hide', edit_mode=util.restore_text( params.get( 'edit_mode', 'False' ) ), message=message, status=status ) @@ -663,7 +706,7 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): else: break return current_samples, details, edit_mode, libraries - + def __library_widgets(self, trans, user, sample_index, libraries, sample=None, lib_id=None, folder_id=None, **kwd): ''' This method creates the data library & folder selectbox for creating & @@ -736,7 +779,6 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): else: folder_widget.add_option(f.name, f.id) return lib_widget, folder_widget - def __copy_sample(self, current_samples): copy_list = SelectField('copy_sample') copy_list.add_option('None', -1, selected=True) @@ -744,6 +786,44 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): copy_list.add_option(s['name'], i) return copy_list + def __sample_operation_selectbox(self, trans, request, **kwd): + params = util.Params( kwd ) + cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) ) + if cntrller == 'requests_admin' and trans.user_is_admin(): + if request.complete(): + bulk_operations = [trans.app.model.Sample.bulk_operations.CHANGE_STATE] + if request.rejected(): + bulk_operations = [trans.app.model.Sample.bulk_operations.SELECT_LIBRARY] + else: + bulk_operations = [s for i, s in trans.app.model.Sample.bulk_operations.items()] + else: + if request.complete(): + bulk_operations = [] + else: + bulk_operations = [trans.app.model.Sample.bulk_operations.SELECT_LIBRARY] + op_list = SelectField('select_sample_operation', + refresh_on_change=True, + refresh_on_change_values=bulk_operations) + sel_op = kwd.get('select_sample_operation', 'none') + if sel_op == 'none': + op_list.add_option('Select operation', 'none', True) + else: + op_list.add_option('Select operation', 'none') + for s in bulk_operations: + if s == sel_op: + op_list.add_option(s, s, True) + else: + op_list.add_option(s, s) + return op_list + + def __selected_samples(self, trans, request, **kwd): + params = util.Params( kwd ) + selected_samples = [] + for s in request.samples: + if CheckboxField.is_checked(params.get('select_sample_%i' % s.id, '')): + selected_samples.append(s.id) + return selected_samples + @web.expose @web.require_login( "create/submit sequencing requests" ) def request_page(self, trans, **kwd): @@ -760,6 +840,15 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): message="Invalid request ID") ) # get the user entered sample details current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd ) + selected_samples = self.__selected_samples(trans, request, **kwd) + sample_ops = self.__sample_operation_selectbox(trans, request,**kwd) + if params.get('select_sample_operation', 'none') != 'none' and not len(selected_samples): + return trans.response.send_redirect( web.url_for( controller=cntrller, + action='list', + operation='show', + id=trans.security.encode_id(request.id), + status='error', + message='Select at least one sample before selecting an operation.' )) if params.get('import_samples_button', False) == 'Import samples': return self.__import_samples(trans, cntrller, request, current_samples, details, libraries, **kwd) elif params.get('add_sample_button', False) == 'Add New': @@ -805,7 +894,8 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): request_details=self.request_details(trans, request.id), current_samples=current_samples, sample_copy=self.__copy_sample(current_samples), - details=details, + details=details, selected_samples=selected_samples, + sample_ops=sample_ops, edit_mode=edit_mode) elif params.get('save_samples_button', False) == 'Save': # check for duplicate sample names @@ -826,11 +916,12 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): if message: return trans.fill_template( '/requests/common/show_request.mako', cntrller=cntrller, - request=request, + request=request, selected_samples=selected_samples, request_details=self.request_details(trans, request.id), current_samples = current_samples, sample_copy=self.__copy_sample(current_samples), details=details, edit_mode=edit_mode, + sample_ops=sample_ops, status='error', message=message) # save all the new/unsaved samples entered by the user if edit_mode == 'False': @@ -899,10 +990,11 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): edit_mode = 'True' return trans.fill_template( '/requests/common/show_request.mako', cntrller=cntrller, - request=request, + request=request, selected_samples=selected_samples, request_details=self.request_details(trans, request.id), current_samples=current_samples, sample_copy=self.__copy_sample(current_samples), + sample_ops=sample_ops, details=details, libraries=libraries, edit_mode=edit_mode) elif params.get('cancel_changes_button', False) == 'Cancel': @@ -910,14 +1002,33 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): action='list', operation='show', id=trans.security.encode_id(request.id)) ) + elif params.get('change_state_button', False) == 'Save': + comments = util.restore_text( params.comment ) + selected_state = int( params.select_state ) + new_state = trans.sa_session.query( trans.app.model.SampleState ).get( selected_state ) + for sample_id in selected_samples: + sample = trans.sa_session.query( trans.app.model.Sample ).get( sample_id ) + event = trans.app.model.SampleEvent(sample, new_state, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() + return trans.response.send_redirect( web.url_for( controller='requests_common', + cntrller=cntrller, + action='update_request_state', + request_id=request.id )) + elif params.get('change_state_button', False) == 'Cancel': + return trans.response.send_redirect( web.url_for( controller=cntrller, + action='list', + operation='show', + id=trans.security.encode_id(request.id)) ) else: return trans.fill_template( '/requests/common/show_request.mako', - cntrller=cntrller, - request=request, + cntrller=cntrller, + request=request, selected_samples=selected_samples, request_details=self.request_details(trans, request.id), current_samples=current_samples, sample_copy=self.__copy_sample(current_samples), details=details, libraries=libraries, + sample_ops=sample_ops, edit_mode=edit_mode, status=status, message=message) def __import_samples(self, trans, cntrller, request, current_samples, details, libraries, **kwd): @@ -1014,21 +1125,12 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): trans.sa_session.delete( s.values ) trans.sa_session.delete( s ) trans.sa_session.flush() - del current_samples[sample_index] return trans.response.send_redirect( web.url_for( controller=cntrller, action='list', operation='show', id=trans.security.encode_id(request.id), status='done', message='Sample %s has been deleted.' % sample_name )) - return trans.fill_template( '/requests/common/show_request.mako', - controller=cntrller, - request=request, - request_details=self.request_details(trans, request.id), - current_samples = current_samples, - sample_copy=self.__copy_sample(current_samples), - details=details, - edit_mode=edit_mode) def request_details(self, trans, id): ''' Shows the request details @@ -1087,11 +1189,10 @@ class RequestsCommon( BaseController, UsesFormDefinitionWidgets ): events_list.append((event.state.name, event.state.desc, time_ago(event.update_time), event.comment)) - widgets, title = self.__change_state_widgets(trans, sample) return trans.fill_template( '/requests/common/sample_events.mako', cntrller=cntrller, events_list=events_list, - sample=sample, widgets=widgets, title=title) + sample=sample) def __change_state_widgets(self, trans, sample): possible_states = sample.request.type.states curr_state = sample.current_state() diff --git a/scripts/galaxy_messaging/server/amqp_consumer.py b/scripts/galaxy_messaging/server/amqp_consumer.py index a1253efb614..89f13026a9f 100644 --- a/scripts/galaxy_messaging/server/amqp_consumer.py +++ b/scripts/galaxy_messaging/server/amqp_consumer.py @@ -108,7 +108,7 @@ def recv_callback(msg): webconfig.get("data_transfer_user_login_info", "email"), webconfig.get("data_transfer_user_login_info", "password"), config.get("app:main", "id_secret")) - galaxyweb.update_request_state(galaxydb.get_request_id(sample_id), sample_id) + galaxyweb.update_request_state(galaxydb.get_request_id(sample_id)) galaxyweb.logout() def main(): diff --git a/scripts/galaxy_messaging/server/galaxyweb_interface.py b/scripts/galaxy_messaging/server/galaxyweb_interface.py index 5875b898c34..2e38c44b3a1 100644 --- a/scripts/galaxy_messaging/server/galaxyweb_interface.py +++ b/scripts/galaxy_messaging/server/galaxyweb_interface.py @@ -106,11 +106,10 @@ class GalaxyWebInterface(object): # Encrypt return id_cipher.encrypt( s ).encode( 'hex' ) - def update_request_state(self, request_id, sample_id): + def update_request_state(self, request_id): params = urllib.urlencode(dict( cntrller='requests_admin', - request_id=request_id, - sample_id=sample_id)) - url = self.base_url + "/requests_admin/update_request_state" + request_id=request_id)) + url = self.base_url + "/requests_common/update_request_state" f = self.opener.open(url, params) print url print params diff --git a/templates/requests/common/sample_events.mako b/templates/requests/common/sample_events.mako index c2eb7dc05f6..4547d6b37b9 100644 --- a/templates/requests/common/sample_events.mako +++ b/templates/requests/common/sample_events.mako @@ -45,28 +45,3 @@ -%if cntrller == 'requests_admin' and trans.user_is_admin(): -
-
Change current state
-
-
- %for w in widgets: -
- - ${w[1].get_html()} - %if w[0] == 'Comments': -
- Optional -
- %endif -
- %endfor -
- -
-
-
-
-%endif \ No newline at end of file diff --git a/templates/requests/common/show_request.mako b/templates/requests/common/show_request.mako index e940a97e0f6..2c95ea3e2e2 100644 --- a/templates/requests/common/show_request.mako +++ b/templates/requests/common/show_request.mako @@ -113,6 +113,36 @@ $(document).ready(function(){ } }); }; + + function checkAllFields() + { + var chkAll = document.getElementById('checkAll'); + var checks = document.getElementsByTagName('input'); + var boxLength = checks.length; + var allChecked = false; + var totalChecked = 0; + if ( chkAll.checked == true ) + { + for ( i=0; i < boxLength; i++ ) + { + if ( checks[i].name.indexOf( 'select_sample_' ) != -1) + { + checks[i].checked = true; + } + } + } + else + { + for ( i=0; i < boxLength; i++ ) + { + if ( checks[i].name.indexOf( 'select_sample_' ) != -1) + { + checks[i].checked = false + } + } + } + } +