details: http://www.bx.psu.edu/hg/galaxy/rev/98fa3b9cd980 changeset: 2586:98fa3b9cd980 user: rc date: Thu Aug 20 10:46:52 2009 -0400 description: Added functional tests for requests & forms LIMS features: - admin can now edit other requests - admin can now submit requests on behalf of other users 11 file(s) affected in this change: lib/galaxy/model/migrate/versions/0009_request_table.py lib/galaxy/web/controllers/library.py lib/galaxy/web/controllers/requests.py lib/galaxy/web/controllers/requests_admin.py templates/admin/requests/edit_request.mako templates/admin/requests/grid.mako templates/admin/requests/new_request.mako templates/admin/requests/show_request.mako templates/requests/grid.mako templates/requests/show_request.mako test/functional/test_forms_and_requests.py diffs (1566 lines): diff -r e66e1e99183c -r 98fa3b9cd980 lib/galaxy/model/migrate/versions/0009_request_table.py --- a/lib/galaxy/model/migrate/versions/0009_request_table.py Fri Aug 14 15:47:13 2009 -0400 +++ b/lib/galaxy/model/migrate/versions/0009_request_table.py Thu Aug 20 10:46:52 2009 -0400 @@ -9,6 +9,7 @@ from migrate.changeset import * import sys, logging from galaxy.model.custom_types import * +from sqlalchemy.exceptions import * log = logging.getLogger( __name__ ) log.setLevel(logging.DEBUG) diff -r e66e1e99183c -r 98fa3b9cd980 lib/galaxy/web/controllers/library.py --- a/lib/galaxy/web/controllers/library.py Fri Aug 14 15:47:13 2009 -0400 +++ b/lib/galaxy/web/controllers/library.py Thu Aug 20 10:46:52 2009 -0400 @@ -1161,3 +1161,13 @@ edit_info=True, msg=util.sanitize_text( msg ), messagetype='done' ) ) + + +def get_authorized_libs(trans, user): + all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all() + authorized_libraries = [] + for library in all_libraries: + if trans.app.security_agent.allow_action(user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) \ + or trans.app.security_agent.allow_action(user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library): + authorized_libraries.append(library) + return authorized_libraries \ No newline at end of file diff -r e66e1e99183c -r 98fa3b9cd980 lib/galaxy/web/controllers/requests.py --- a/lib/galaxy/web/controllers/requests.py Fri Aug 14 15:47:13 2009 -0400 +++ b/lib/galaxy/web/controllers/requests.py Thu Aug 20 10:46:52 2009 -0400 @@ -9,6 +9,7 @@ from datetime import datetime, timedelta from cgi import escape, FieldStorage from galaxy.web.controllers.forms import get_form_widgets +from galaxy.web.controllers.library import get_authorized_libs log = logging.getLogger( __name__ ) @@ -66,15 +67,7 @@ @web.require_login( "create/submit sequencing requests" ) def index( self, trans ): return trans.fill_template( "requests/index.mako" ) - - def get_authorized_libs(self, trans): - all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all() - authorized_libraries = [] - for library in all_libraries: - if trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) \ - or trans.app.security_agent.allow_action(trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library): - authorized_libraries.append(library) - return authorized_libraries + @web.expose @web.require_login( "create/submit sequencing requests" ) def list( self, trans, **kwargs ): @@ -140,7 +133,6 @@ Shows the request details ''' request = trans.app.model.Request.get(id) - libraries = self.get_authorized_libs(trans) # list of widgets to be rendered on the request form request_details = [] # main details @@ -424,8 +416,8 @@ if params.get('create_request_button', False) == 'Save': return trans.response.send_redirect( web.url_for( controller='requests', action='list', - msg=msg , - messagetype='done') ) + message=msg , + status='done') ) elif params.get('create_request_samples_button', False) == 'Add samples': new_kwd = {} new_kwd['id'] = trans.security.encode_id(request.id) @@ -468,7 +460,7 @@ helptext='(Optional)')) # libraries selectbox - libraries = self.get_authorized_libs(trans) + libraries = get_authorized_libs(trans, trans.user) libui = self.__library_ui(libraries, **kwd) widgets = widgets + libui widgets = widgets + get_form_widgets(trans, request_type.request_form, contents=[], **kwd) @@ -517,8 +509,8 @@ Validates the request entered by the user ''' empty_fields = [] - if not request.library: - empty_fields.append('Library') +# if not request.library: +# empty_fields.append('Library') # check rest of the fields of the form for index, field in enumerate(request.type.request_form.fields): if field['required'] == 'required' and request.values.content[index] in ['', None]: @@ -664,7 +656,7 @@ helptext='(Optional)')) # libraries selectbox - libraries = self.get_authorized_libs(trans) + libraries = get_authorized_libs(trans, trans.user) libui = self.__library_ui(libraries, request, **kwd) widgets = widgets + libui widgets = widgets + get_form_widgets(trans, request.type.request_form, request.values.content, **kwd) @@ -700,6 +692,8 @@ kwd['id'] = trans.security.encode_id(request.id) return trans.response.send_redirect( web.url_for( controller='requests', action='list', + status='done', + message='The request <b>%s</b> has been deleted.' % request.name, **kwd) ) def __undelete_request(self, trans, id): try: @@ -719,6 +713,8 @@ kwd['id'] = trans.security.encode_id(request.id) return trans.response.send_redirect( web.url_for( controller='requests', action='list', + status='done', + message='The request <b>%s</b> has been undeleted.' % request.name, **kwd) ) def __submit(self, trans, id): try: diff -r e66e1e99183c -r 98fa3b9cd980 lib/galaxy/web/controllers/requests_admin.py --- a/lib/galaxy/web/controllers/requests_admin.py Fri Aug 14 15:47:13 2009 -0400 +++ b/lib/galaxy/web/controllers/requests_admin.py Thu Aug 20 10:46:52 2009 -0400 @@ -7,19 +7,20 @@ import logging, tempfile, zipfile, tarfile, os, sys from galaxy.web.form_builder import * from datetime import datetime, timedelta +from galaxy.web.controllers.forms import get_form_widgets +from galaxy.web.controllers.library import get_authorized_libs log = logging.getLogger( __name__ ) - -# States for passing messages -SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error" class RequestsListGrid( grids.Grid ): title = "Sequencing Requests" model_class = model.Request default_sort_key = "-create_time" + show_filter = model.Request.states.SUBMITTED columns = [ grids.GridColumn( "Name", key="name", - link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) )), + link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), + attach_popup=True ), grids.GridColumn( "Description", key="desc"), grids.GridColumn( "Sample(s)", method='number_of_samples', link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ), @@ -30,15 +31,18 @@ ] operations = [ -# grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ), -# grids.GridOperation( "Samples", allow_multiple=False, condition=( lambda item: not item.deleted ) ), -# grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ) ), -# grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), + grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ) ), + grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Delete", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), ] standard_filters = [ + grids.GridColumnFilter( model.Request.states.UNSUBMITTED, + args=dict( state=model.Request.states.UNSUBMITTED, deleted=False ) ), grids.GridColumnFilter( model.Request.states.SUBMITTED, args=dict( state=model.Request.states.SUBMITTED, deleted=False ) ), grids.GridColumnFilter( model.Request.states.COMPLETE, args=dict( state=model.Request.states.COMPLETE, deleted=False ) ), + grids.GridColumnFilter( "Deleted", args=dict( deleted=True ) ), grids.GridColumnFilter( "All", args=dict( deleted=False ) ) ] def get_user(self, trans, request): @@ -48,9 +52,9 @@ def get_request_type(self, trans, request): request_type = trans.app.model.RequestType.get(request.request_type_id) return request_type.name - def apply_default_filter( self, trans, query ): - return query.filter(or_(self.model_class.state==self.model_class.states.SUBMITTED, - self.model_class.state==self.model_class.states.COMPLETE)) +# def apply_default_filter( self, trans, query ): +# return query.filter(or_(self.model_class.state==self.model_class.states.SUBMITTED, +# self.model_class.state==self.model_class.states.COMPLETE)) def number_of_samples(self, trans, request): return str(len(request.samples)) @@ -75,14 +79,256 @@ if operation == "show_request": id = trans.security.decode_id(kwargs['id']) return self.__show_request(trans, id) - + elif operation == "submit": + id = trans.security.decode_id(kwargs['id']) + return self.__submit(trans, id) + elif operation == "edit": + id = trans.security.decode_id(kwargs['id']) + return self.__edit_request(trans, id) + elif operation == "delete": + id = trans.security.decode_id(kwargs['id']) + return self.__delete_request(trans, id) + elif operation == "undelete": + id = trans.security.decode_id(kwargs['id']) + return self.__undelete_request(trans, id) if 'show_filter' in kwargs.keys(): if kwargs['show_filter'] == 'All': - self.request_grid.default_filter = dict(deleted=False) + self.request_grid.default_filter = {} + elif kwargs['show_filter'] == 'Deleted': + self.request_grid.default_filter = dict(deleted=True) else: - self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) + self.request_grid.default_filter = dict(state=kwargs['show_filter'], deleted=False) + self.request_grid.show_filter = kwargs.get('show_filter', trans.app.model.Request.states.SUBMITTED) # Render the list view return self.request_grid( trans, template='/admin/requests/grid.mako', **kwargs ) + @web.expose + @web.require_admin + def edit(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + try: + request = trans.app.model.Request.get(int(params.get('request_id', None))) + except: + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message="Invalid request ID", + **kwd) ) + if params.get('show', False) == 'True': + return self.__edit_request(trans, request.id, **kwd) + elif params.get('save_changes_request_button', False) == 'Save changes' \ + or params.get('edit_samples_button', False) == 'Edit samples': + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + if not util.restore_text(params.get('name', '')): + msg = 'Please enter the <b>Name</b> of the request' + kwd['messagetype'] = 'error' + kwd['msg'] = msg + kwd['show'] = 'True' + return trans.response.send_redirect( web.url_for( controller='requests', + action='edit', + **kwd) ) + request = self.__save_request(trans, request, **kwd) + msg = 'The changes made to the request named %s has been saved' % request.name + if params.get('save_changes_request_button', False) == 'Save changes': + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + message=msg , + status='done') ) + elif params.get('edit_samples_button', False) == 'Edit samples': + new_kwd = {} + new_kwd['request_id'] = request.id + new_kwd['edit_samples_button'] = 'Edit samples' + return trans.response.send_redirect( web.url_for( controller='requests', + action='show_request', + msg=msg , + messagetype='done', + **new_kwd) ) + elif params.get('refresh', False) == 'true': + return self.__edit_request(trans, request.id, **kwd) + def __edit_request(self, trans, id, **kwd): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message=msg) ) + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + select_request_type = self.__select_request_type(trans, request.type.id) + # list of widgets to be rendered on the request form + widgets = [] + if util.restore_text( params.get( 'name', '' ) ): + name = util.restore_text( params.get( 'name', '' ) ) + else: + name = request.name + widgets.append(dict(label='Name', + widget=TextField('name', 40, name), + helptext='(Required)')) + if util.restore_text( params.get( 'desc', '' ) ): + desc = util.restore_text( params.get( 'desc', '' ) ) + else: + desc = request.desc + widgets.append(dict(label='Description', + widget=TextField('desc', 40, desc), + helptext='(Optional)')) + # libraries selectbox + libraries = get_authorized_libs(trans, trans.user) + libui = self.__library_ui(libraries, request, **kwd) + widgets = widgets + libui + widgets = widgets + get_form_widgets(trans, request.type.request_form, request.values.content, **kwd) + return trans.fill_template( '/admin/requests/edit_request.mako', + select_request_type=select_request_type, + request_type=request.type, + request=request, + widgets=widgets, + msg=msg, + messagetype=messagetype) + return self.__show_request_form(trans) + def __delete_request(self, trans, id): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message=msg, + **kwd) ) + # change request's submitted field + if not request.unsubmitted(): + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message='This request cannot be deleted as it is already been submitted', + **kwd) ) + request.deleted = True + request.flush() + kwd = {} + kwd['id'] = trans.security.encode_id(request.id) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='done', + message='The request <b>%s</b> has been deleted.' % request.name, + **kwd) ) + def __undelete_request(self, trans, id): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message=msg, + **kwd) ) + # change request's submitted field + request.deleted = False + request.flush() + kwd = {} + kwd['id'] = trans.security.encode_id(request.id) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='done', + message='The request <b>%s</b> has been undeleted.' % request.name, + **kwd) ) + def __submit(self, trans, id): + try: + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message=msg, + **kwd) ) + msg = self.__validate(trans, request) + if msg: + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='edit', + messagetype = 'error', + msg=msg, + request_id=request.id, + show='True') ) + # get the new state + new_state = request.type.states[0] + for s in request.samples: + event = trans.app.model.SampleEvent(s, new_state, 'Samples submitted to the system') + event.flush() + # change request's submitted field + request.state = request.states.SUBMITTED + request.flush() + kwd = {} + kwd['id'] = trans.security.encode_id(request.id) + kwd['status'] = 'done' + kwd['message'] = 'The request <b>%s</b> has been submitted.' % request.name + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + show_filter=trans.app.model.Request.states.SUBMITTED, + **kwd) ) + @web.expose + @web.require_admin + def submit_request(self, trans, **kwd): + params = util.Params( kwd ) + try: + id = int(params.get('id', False)) + request = trans.app.model.Request.get(id) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message=msg, + **kwd) ) + msg = self.__validate(trans, request) + if msg: + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='edit', + messagetype = 'error', + msg=msg, + request_id=request.id, + show='True') ) + # get the new state + new_state = request.type.states[0] + for s in request.samples: + event = trans.app.model.SampleEvent(s, new_state, 'Samples submitted to the system') + event.flush() + # change request's submitted field + request.state = request.states.SUBMITTED + request.flush() + kwd['id'] = trans.security.encode_id(request.id) + kwd['status'] = 'done' + kwd['message'] = 'The request <b>%s</b> has been submitted.' % request.name + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + show_filter=trans.app.model.Request.states.SUBMITTED, + **kwd) ) + def __copy_sample(self): + copy_list = SelectField('copy_sample') + copy_list.add_option('None', -1, selected=True) + for i, s in enumerate(self.current_samples): + copy_list.add_option(s[0], i) + return copy_list + def __update_samples(self, request, **kwd): + params = util.Params( kwd ) + num_samples = len(self.current_samples) + self.current_samples = [] + for s in request.samples: + self.current_samples.append([s.name, s.values.content]) + for index in range(num_samples-len(request.samples)): + sample_index = index + len(request.samples) + sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) + sample_values = [] + for field_index in range(len(request.type.sample_form.fields)): + sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) + self.current_samples.append([sample_name, sample_values]) def __show_request(self, trans, id): try: request = trans.app.model.Request.get(id) @@ -93,6 +339,7 @@ message="Invalid request ID", **kwd) ) self.current_samples = [] + self.edit_mode = False for s in request.samples: self.current_samples.append([s.name, s.values.content]) self.details_state = 'Show request details' @@ -100,8 +347,160 @@ request=request, request_details=self.request_details(trans, id), current_samples = self.current_samples, - details_state=self.details_state) + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) @web.expose + @web.require_admin + def show_request(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + try: + request = 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) ) + if params.get('import_samples_button', False) == 'Import samples': + try: + file_obj = params.get('file_data', '') + import csv + reader = csv.reader(file_obj.file) + for row in reader: + self.current_samples.append([row[0], row[1:]]) + return trans.fill_template( '/admin/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + except: + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + status='error', + message='Error in importing <b>%s</b> samples file' % file_obj.file, + **kwd)) + elif params.get('add_sample_button', False) == 'Add New': + # save the all (saved+unsaved) sample info in 'current_samples' + self.__update_samples(request, **kwd) + # add an empty or filled sample + # if the user has selected a sample no. to copy then copy the contents + # of the src sample to the new sample else an empty sample + src_sample_index = int(params.get( 'copy_sample', -1 )) + if src_sample_index == -1: + # empty sample + self.current_samples.append(['Sample_%i' % (len(self.current_samples)+1),['' for field in request.type.sample_form.fields]]) + else: + self.current_samples.append([self.current_samples[src_sample_index][0]+'_%i' % (len(self.current_samples)+1), + [val for val in self.current_samples[src_sample_index][1]]]) + return trans.fill_template( '/admin/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + elif params.get('save_samples_button', False) == 'Save': + # update current_samples + self.__update_samples(request, **kwd) + # check for duplicate sample names + msg = '' + for index in range(len(self.current_samples)-len(request.samples)): + sample_index = index + len(request.samples) + sample_name = self.current_samples[sample_index][0] + if not sample_name.strip(): + msg = 'Please enter the name of sample number %i' % sample_index + break + count = 0 + for i in range(len(self.current_samples)): + if sample_name == self.current_samples[i][0]: + count = count + 1 + if count > 1: + msg = "This request has <b>%i</b> samples with the name <b>%s</b>.\nSamples belonging to a request must have unique names." % (count, sample_name) + break + if msg: + return trans.fill_template( '/admin/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples = self.current_samples, + sample_copy=self.__copy_sample(), details_state=self.details_state, + messagetype='error', msg=msg) + # save all the new/unsaved samples entered by the user + if not self.edit_mode: + for index in range(len(self.current_samples)-len(request.samples)): + sample_index = index + len(request.samples) + sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) + sample_values = [] + for field_index in range(len(request.type.sample_form.fields)): + sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) + form_values = trans.app.model.FormValues(request.type.sample_form, sample_values) + form_values.flush() + s = trans.app.model.Sample(sample_name, '', request, form_values) + s.flush() + else: + for index in range(len(self.current_samples)): + sample_index = index + sample_name = self.current_samples[sample_index][0] + new_sample_name = util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ) + sample_values = [] + for field_index in range(len(request.type.sample_form.fields)): + sample_values.append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) )) + sample = request.has_sample(sample_name) + if sample: + form_values = trans.app.model.FormValues.get(sample.values.id) + form_values.content = sample_values + form_values.flush() + sample.name = new_sample_name + sample.flush() + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + operation='show_request', + id=trans.security.encode_id(request.id)) ) + elif params.get('edit_samples_button', False) == 'Edit samples': + self.edit_mode = True + return trans.fill_template( '/admin/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples=self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + elif params.get('cancel_changes_button', False) == 'Cancel': + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + operation='show_request', + id=trans.security.encode_id(request.id)) ) + + + @web.expose + @web.require_admin + def delete_sample(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + request = trans.app.model.Request.get(int(params.get('request_id', 0))) + sample_index = int(params.get('sample_id', 0)) + sample_name = self.current_samples[sample_index][0] + s = request.has_sample(sample_name) + if s: + s.delete() + s.flush() + request.flush() + del self.current_samples[sample_index] + return trans.fill_template( '/admin/requests/show_request.mako', + request=request, + request_details=self.request_details(trans, request.id), + current_samples = self.current_samples, + sample_copy=self.__copy_sample(), + details_state=self.details_state, + edit_mode=self.edit_mode) + + @web.expose + @web.require_admin def toggle_request_details(self, trans, **kwd): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) @@ -144,10 +543,16 @@ value=str(request.user.email), helptext='')) # library associated - request_details.append(dict(label='Library', - value=trans.app.model.Library.get(request.library_id).name, - helptext='Associated library where the resultant \ - dataset will be stored')) + if request.library: + request_details.append(dict(label='Library', + value=request.library.name, + helptext='Associated library where the resultant \ + dataset will be stored')) + else: + request_details.append(dict(label='Library', + value=None, + helptext='Associated library where the resultant \ + dataset will be stored')) # form fields for index, field in enumerate(request.type.request_form.fields): if field['required']: @@ -168,6 +573,253 @@ value=request.values.content[index], helptext=field['helptext']+' ('+req+')')) return request_details + + def __select_request_type(self, trans, rtid): + rt_ids = ['none'] + for rt in trans.app.model.RequestType.query().all(): + if not rt.deleted: + rt_ids.append(str(rt.id)) + select_reqtype = SelectField('select_request_type', + refresh_on_change=True, + refresh_on_change_values=rt_ids[1:]) + if rtid == 'none': + select_reqtype.add_option('Select one', 'none', selected=True) + else: + select_reqtype.add_option('Select one', 'none') + for rt in trans.app.model.RequestType.query().all(): + if not rt.deleted: + if rtid == rt.id: + select_reqtype.add_option(rt.name, rt.id, selected=True) + else: + select_reqtype.add_option(rt.name, rt.id) + return select_reqtype + @web.expose + @web.require_admin + def new(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + if params.get('select_request_type', False) == 'True': + return trans.fill_template( '/admin/requests/new_request.mako', + select_request_type=self.__select_request_type(trans, 'none'), + widgets=[], + msg=msg, + messagetype=messagetype) + elif params.get('create', False) == 'True': + if params.get('create_request_button', False) == 'Save' \ + or params.get('create_request_samples_button', False) == 'Add samples': + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + if not util.restore_text(params.get('name', '')) \ + or util.restore_text(params.get('select_user', '')) == unicode('none'): + msg = 'Please enter the <b>Name</b> of the request and the <b>user</b> on behalf of whom this request will be submitted before saving this request' + kwd['create'] = 'True' + kwd['messagetype'] = 'error' + kwd['msg'] = msg + kwd['create_request_button'] = None + kwd['create_request_samples_button'] = None + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='new', + **kwd) ) + request = self.__save_request(trans, None, **kwd) + msg = 'The new request named %s has been created' % request.name + if params.get('create_request_button', False) == 'Save': + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + show_filter=trans.app.model.Request.states.UNSUBMITTED, + message=msg , + status='done') ) + elif params.get('create_request_samples_button', False) == 'Add samples': + new_kwd = {} + new_kwd['id'] = trans.security.encode_id(request.id) + new_kwd['operation'] = 'show_request' + new_kwd['add_sample'] = True + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + message=msg , + status='done', + **new_kwd) ) + else: + return self.__show_request_form(trans, **kwd) + elif params.get('refresh', False) == 'true': + return self.__show_request_form(trans, **kwd) + def __show_request_form(self, trans, **kwd): + params = util.Params( kwd ) + msg = util.restore_text( params.get( 'msg', '' ) ) + messagetype = params.get( 'messagetype', 'done' ) + try: + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + except: + return trans.fill_template( '/admin/requests/new_request.mako', + select_request_type=self.__select_request_type(trans, 'none'), + widgets=[], + msg=msg, + messagetype=messagetype) + form_values = None + select_request_type = self.__select_request_type(trans, request_type.id) + # user + user_id = params.get( 'select_user', 'none' ) + try: + user = trans.app.model.User.get(int(user_id)) + except: + user = None + # list of widgets to be rendered on the request form + widgets = [] + widgets.append(dict(label='Select user', + widget=self.__select_user(trans, user_id), + helptext='The request would be submitted on behalf of this user (Required)')) + widgets.append(dict(label='Name', + widget=TextField('name', 40, + util.restore_text( params.get( 'name', '' ) )), + helptext='(Required)')) + widgets.append(dict(label='Description', + widget=TextField('desc', 40, + util.restore_text( params.get( 'desc', '' ) )), + helptext='(Optional)')) + # libraries selectbox + if not user: + libraries = [] + else: + libraries = get_authorized_libs(trans, user) + libui = self.__library_ui(libraries, **kwd) + widgets = widgets + libui + widgets = widgets + get_form_widgets(trans, request_type.request_form, contents=[], **kwd) + return trans.fill_template( '/admin/requests/new_request.mako', + select_request_type=select_request_type, + request_type=request_type, + widgets=widgets, + msg=msg, + messagetype=messagetype) + def __select_user(self, trans, userid): + user_ids = ['none'] + for user in trans.app.model.User.query().all(): + if not user.deleted: + user_ids.append(str(user.id)) + select_user = SelectField('select_user', + refresh_on_change=True, + refresh_on_change_values=user_ids[1:]) + if userid == 'none': + select_user.add_option('Select one', 'none', selected=True) + else: + select_user.add_option('Select one', 'none') + for user in trans.app.model.User.query().all(): + if not user.deleted: + if userid == str(user.id): + select_user.add_option(user.email, user.id, selected=True) + else: + select_user.add_option(user.email, user.id) + return select_user + + def __library_ui(self, libraries, request=None, **kwd): + params = util.Params( kwd ) + lib_id = params.get( 'library_id', 'none' ) + lib_list = SelectField('library_id', refresh_on_change=True, + refresh_on_change_values=['new']) + if request and lib_id == 'none': + if request.library: + lib_id = str(request.library.id) + if lib_id == 'none': + lib_list.add_option('Select one', 'none', selected=True) + else: + lib_list.add_option('Select one', 'none') + for lib in libraries: + if str(lib.id) == lib_id: + lib_list.add_option(lib.name, lib.id, selected=True) + else: + lib_list.add_option(lib.name, lib.id) + if lib_id == 'new': + lib_list.add_option('Create a new library', 'new', selected=True) + else: + lib_list.add_option('Create a new library', 'new') + widget = dict(label='Library', + widget=lib_list, + helptext='Associated library where the resultant \ + dataset will be stored.') + if lib_id == 'new': + new_lib = dict(label='Create a new Library', + widget=TextField('new_library_name', 40, + util.restore_text( params.get( 'new_library_name', '' ) )), + helptext='Enter a library name here to request a new library') + return [widget, new_lib] + else: + return [widget] + def __validate(self, trans, request): + ''' + Validates the request entered by the user + ''' + empty_fields = [] +# if not request.library: +# empty_fields.append('Library') + # check rest of the fields of the form + for index, field in enumerate(request.type.request_form.fields): + if field['required'] == 'required' and request.values.content[index] in ['', None]: + empty_fields.append(field['label']) + if empty_fields: + msg = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name + for ef in empty_fields: + msg = msg + '<b>' +ef + '</b><br/>' + return msg + return None + def __save_request(self, trans, request=None, **kwd): + ''' + This method saves a new request if request_id is None. + ''' + params = util.Params( kwd ) + request_type = trans.app.model.RequestType.get(int(params.select_request_type)) + if request: + user = request.user + else: + user = trans.app.model.User.get(int(params.get('select_user', ''))) + name = util.restore_text(params.get('name', '')) + desc = util.restore_text(params.get('desc', '')) + # library + try: + library = trans.app.model.Library.get(int(params.get('library_id', None))) + except: + library = None + # fields + values = [] + for index, field in enumerate(request_type.request_form.fields): + if field['type'] == 'AddressField': + value = util.restore_text(params.get('field_%i' % index, '')) + if value == 'new': + # save this new address in the list of this user's addresses + user_address = trans.app.model.UserAddress( user=trans.user ) + user_address.desc = util.restore_text(params.get('field_%i_short_desc' % index, '')) + user_address.name = util.restore_text(params.get('field_%i_name' % index, '')) + user_address.institution = util.restore_text(params.get('field_%i_institution' % index, '')) + user_address.address = util.restore_text(params.get('field_%i_address1' % index, ''))+' '+util.restore_text(params.get('field_%i_address2' % index, '')) + user_address.city = util.restore_text(params.get('field_%i_city' % index, '')) + user_address.state = util.restore_text(params.get('field_%i_state' % index, '')) + user_address.postal_code = util.restore_text(params.get('field_%i_postal_code' % index, '')) + user_address.country = util.restore_text(params.get('field_%i_country' % index, '')) + user_address.phone = util.restore_text(params.get('field_%i_phone' % index, '')) + user_address.flush() + trans.user.refresh() + values.append(int(user_address.id)) + elif value == unicode('none'): + values.append('') + else: + values.append(int(value)) + else: + values.append(util.restore_text(params.get('field_%i' % index, ''))) + form_values = trans.app.model.FormValues(request_type.request_form, values) + form_values.flush() + if not request: + request = trans.app.model.Request(name, desc, request_type, + user, form_values, + library=library, + state=trans.app.model.Request.states.UNSUBMITTED) + request.flush() + else: + request.name = name + request.desc = desc + request.type = request_type + request.user = user + request.values = form_values + request.library = library + request.state = trans.app.model.Request.states.UNSUBMITTED + request.flush() + return request @web.expose @web.require_admin def bar_codes(self, trans, **kwd): @@ -178,7 +830,7 @@ if request_id: request = trans.app.model.Request.get( int( request_id )) if not request: - return trans.response.send_redirect( web.url_for( controller='requests', + return trans.response.send_redirect( web.url_for( controller='requests_admin', action='list', status='error', message="Invalid request ID", @@ -204,7 +856,7 @@ try: request = trans.app.model.Request.get(int(params.get('request_id', None))) except: - return trans.response.send_redirect( web.url_for( controller='requests', + return trans.response.send_redirect( web.url_for( controller='requests_admin', action='list', status='error', message="Invalid request ID", diff -r e66e1e99183c -r 98fa3b9cd980 templates/admin/requests/edit_request.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/admin/requests/edit_request.mako Thu Aug 20 10:46:52 2009 -0400 @@ -0,0 +1,88 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +<script type="text/javascript"> +$( function() { + $( "select[refresh_on_change='true']").change( function() { + var refresh = false; + var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' ) + if ( refresh_on_change_values ) { + refresh_on_change_values = refresh_on_change_values.value.split( ',' ); + var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' ); + for( i= 0; i < refresh_on_change_values.length; i++ ) { + if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){ + refresh = true; + break; + } + } + } + else { + refresh = true; + } + if ( refresh ){ + $( "#edit_request" ).submit(); + } + }); +}); +</script> + +<br/> +<br/> +<ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='show_request', id=trans.security.encode_id(request.id) )}"> + <span>Browse this request</span></a> + </li> + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='list')}"> + <span>Browse requests</span></a> + </li> +</ul> + +<div class="toolForm"> + <div class="toolFormTitle">Edit request "${request.name}" from ${request.user.email}</div> + %if len(select_request_type.options) == 1: + There are no request types created for a new request. + %else: + <div class="toolFormBody"> + <form name="edit_request" id="edit_request" action="${h.url_for( controller='requests_admin', action='edit', request_id=request.id)}" method="post" > + <div class="form-row"> + <label> + Select Request Type: + </label> + ${select_request_type.get_html()} + </div> + + %if select_request_type.get_selected() != ('Select one', 'none'): + %for i, field in enumerate(widgets): + <div class="form-row"> + <label>${field['label']}</label> + ${field['widget'].get_html()} + %if field['label'] == 'Library' and new_library: + ${new_library.get_html()} + %endif + <div class="toolParamHelp" style="clear: both;"> + ${field['helptext']} + </div> + <div style="clear: both"></div> + </div> + %endfor + <div class="form-row"> + <div style="float: left; width: 250px; margin-right: 10px;"> + <input type="hidden" name="refresh" value="true" size="40"/> + </div> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" name="save_changes_request_button" value="Save changes"/> + ##<input type="submit" name="edit_samples_button" value="Edit samples"/> + </div> + %endif + </form> + </div> +</div> +%endif \ No newline at end of file diff -r e66e1e99183c -r 98fa3b9cd980 templates/admin/requests/grid.mako --- a/templates/admin/requests/grid.mako Fri Aug 14 15:47:13 2009 -0400 +++ b/templates/admin/requests/grid.mako Thu Aug 20 10:46:52 2009 -0400 @@ -82,23 +82,22 @@ %if i > 0: <span>|</span> %endif - %if 'state' in grid.default_filter: - %if grid.default_filter['state'] == filter.label: - <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}"><b>${filter.label}</b></a></span> - %else: - <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}">${filter.label}</a></span> - %endif + %if grid.show_filter == filter.label: + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}"><b>${filter.label}</b></a></span> %else: - %if filter.label == 'All': - <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}"><b>${filter.label}</b></a></span> - %else: - <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}">${filter.label}</a></span> - %endif + <span class="filter"><a href="${h.url_for( controller='requests_admin', action='list', show_filter=filter.label )}">${filter.label}</a></span> %endif %endfor %endif </div> +<ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='new', select_request_type=True )}"> + <img src="${h.url_for('/static/images/silk/add.png')}" /> + <span>Create a new request</span></a> + </li> +</ul> %if not len(query.all()): There are no request(s). diff -r e66e1e99183c -r 98fa3b9cd980 templates/admin/requests/new_request.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/admin/requests/new_request.mako Thu Aug 20 10:46:52 2009 -0400 @@ -0,0 +1,84 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +<script type="text/javascript"> +$( function() { + $( "select[refresh_on_change='true']").change( function() { + var refresh = false; + var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' ) + if ( refresh_on_change_values ) { + refresh_on_change_values = refresh_on_change_values.value.split( ',' ); + var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' ); + for( i= 0; i < refresh_on_change_values.length; i++ ) { + if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){ + refresh = true; + break; + } + } + } + else { + refresh = true; + } + if ( refresh ){ + $( "#new_request" ).submit(); + } + }); +}); +</script> + +<br/> +<br/> +<ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='list')}"> + <span>Browse requests</span></a> + </li> +</ul> + +<div class="toolForm"> + <div class="toolFormTitle">Add a new request</div> + %if len(select_request_type.options) == 1: + There are no request types created for a new request. + %else: + <div class="toolFormBody"> + <form name="new_request" id="new_request" action="${h.url_for( controller='requests_admin', action='new', create=True )}" method="post" > + <div class="form-row"> + <label> + Select Request Type + </label> + ${select_request_type.get_html()} + </div> + + %if select_request_type.get_selected() != ('Select one', 'none'): + %for i, field in enumerate(widgets): + <div class="form-row"> + <label>${field['label']}</label> + ${field['widget'].get_html()} + %if field['label'] == 'Library' and new_library: + ${new_library.get_html()} + %endif + <div class="toolParamHelp" style="clear: both;"> + ${field['helptext']} + </div> + <div style="clear: both"></div> + </div> + %endfor + <div class="form-row"> + <div style="float: left; width: 250px; margin-right: 10px;"> + <input type="hidden" name="refresh" value="true" size="40"/> + </div> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" name="create_request_button" value="Save"/> + <input type="submit" name="create_request_samples_button" value="Add samples"/> + </div> + %endif + </form> + </div> +</div> +%endif \ No newline at end of file diff -r e66e1e99183c -r 98fa3b9cd980 templates/admin/requests/show_request.mako --- a/templates/admin/requests/show_request.mako Fri Aug 14 15:47:13 2009 -0400 +++ b/templates/admin/requests/show_request.mako Thu Aug 20 10:46:52 2009 -0400 @@ -12,18 +12,49 @@ </div> <ul class="manage-table-actions"> - <li> - <a class="action-button" href="${h.url_for( controller='requests_admin', action='bar_codes', request_id=request.id)}"> - <span>Bar codes</span></a> - </li> + %if request.unsubmitted() and request.samples: + <li> + <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_admin', action='submit_request', id=request.id)}"> + <span>Submit request</span></a> + </li> + %endif + %if request.submitted() and request.samples: + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='bar_codes', request_id=request.id)}"> + <span>Bar codes</span></a> + </li> + %endif </ul> + +<%def name="render_sample_form( index, sample_name, sample_values )"> + <td> + <input type="text" name=sample_${index}_name value="${sample_name}" size="10"/> + <div class="toolParamHelp" style="clear: both;"> + <i>${' (required)' }</i> + </div> + </td> + <td> + </td> + %for field_index, field in enumerate(request.type.sample_form.fields): + <td> + <input type="text" name=sample_${index}_field_${field_index} value="${sample_values[field_index]}" size="7"/> + <div class="toolParamHelp" style="clear: both;"> + <i>${'('+field['required']+')' }</i> + </div> + </td> + %endfor +</%def> <%def name="render_sample( index, sample )"> <td> ${sample.name} </td> <td> - <a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a> + %if sample.request.unsubmitted(): + Unsubmitted + %else: + <a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a> + %endif </td> %for field_index, field in enumerate(request.type.sample_form.fields): <td> @@ -34,10 +65,10 @@ %endif </td> %endfor + </%def> <div class="toolForm"> - ##<div class="toolFormTitle">Request Details: '${request_details[0]['value']}'</div> <div class="form-row"> <a href="${h.url_for( controller='requests_admin', action='toggle_request_details', request_id=request.id )}">${details_state}</a> </div> @@ -57,13 +88,21 @@ </div> <div style="clear: both"></div> %endfor + <div class="form-row"> + <ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='edit', show=True, request_id=request.id)}"> + <span>Edit request details</span></a> + </li> + </ul> + </div> %endif </div> </div> <div class="toolForm"> ##<div class="toolFormTitle">Samples (${len(request.samples)})</div> - <form id="edit_form" name="edit_form" action="${h.url_for( controller='requests', action='show_request', request_id=request.id )}" method="post" > + <form id="edit_form" name="edit_form" action="${h.url_for( controller='requests_admin', action='show_request' )}" enctype="multipart/form-data" method="post" > <div class="form-row"> %if current_samples: <table class="grid"> @@ -80,22 +119,88 @@ </div> </th> %endfor + <th></th> </tr> <thead> <tbody> + <% + request.refresh() + %> %for sample_index, sample in enumerate(current_samples): - <tr> - <td>${sample_index+1}</td> - ${render_sample( sample_index, request.samples[sample_index] )} - </tr> + %if edit_mode: + <tr> + <td>${sample_index+1}</td> + ${render_sample_form( sample_index, sample[0], sample[1])} + </tr> + %else: + <tr> + <td>${sample_index+1}</td> + %if sample_index in range(len(request.samples)): + ${render_sample( sample_index, request.samples[sample_index] )} + %else: + ${render_sample_form( sample_index, sample[0], sample[1])} + %endif + <td> + %if request.unsubmitted(): + <a class="action-button" href="${h.url_for( controller='requests_admin', action='delete_sample', request_id=request.id, sample_id=sample_index)}"> + <img src="${h.url_for('/static/images/delete_icon.png')}" /> + <span></span></a> + %endif + </td> + </tr> + %endif %endfor </tbody> </table> %else: <label>There are no samples.</label> %endif - </div> - ##</div> + %if not edit_mode: + <table class="grid"> + <tbody> + <tr> + <div class="form-row"> + <td> + %if current_samples: + <input type="submit" name="edit_samples_button" value="Edit samples"/> + %endif + </td> + %if request.unsubmitted(): + <td> + <label>Import from csv file</label> + <input type="file" name="file_data" /> + <input type="submit" name="import_samples_button" value="Import samples"/> + </td> + <td> + %if current_samples: + <label>Copy from sample</label> + ${sample_copy.get_html()} + %endif + <input type="submit" name="add_sample_button" value="Add New"/> + </td> + %endif + </div> + </tr> + </tbody> + </table> + %endif + %if request.samples or current_samples: + <div class="form-row"> + <div style="float: left; width: 250px; margin-right: 10px;"> + <input type="hidden" name="refresh" value="true" size="40"/> + </div> + <div style="clear: both"></div> + </div> + <div class="form-row"> + %if edit_mode: + <input type="submit" name="save_samples_button" value="Save"/> + <input type="submit" name="cancel_changes_button" value="Cancel"/> + %elif request.unsubmitted(): + <input type="submit" name="save_samples_button" value="Save"/> + %endif + </div> + %endif + <input type="hidden" name="request_id" value="${request.id}" /> </form> </div> diff -r e66e1e99183c -r 98fa3b9cd980 templates/requests/grid.mako --- a/templates/requests/grid.mako Fri Aug 14 15:47:13 2009 -0400 +++ b/templates/requests/grid.mako Thu Aug 20 10:46:52 2009 -0400 @@ -95,7 +95,7 @@ <li> <a class="action-button" href="${h.url_for( controller='requests', action='new', select_request_type=True )}"> <img src="${h.url_for('/static/images/silk/add.png')}" /> - <span>New request</span></a> + <span>Create a new request</span></a> </li> </ul> diff -r e66e1e99183c -r 98fa3b9cd980 templates/requests/show_request.mako --- a/templates/requests/show_request.mako Fri Aug 14 15:47:13 2009 -0400 +++ b/templates/requests/show_request.mako Thu Aug 20 10:46:52 2009 -0400 @@ -68,7 +68,6 @@ </%def> <div class="toolForm"> - ##<div class="toolFormTitle">Request Details: '${request_details[0]['value']}'</div> <div class="form-row"> <a href="${h.url_for( controller='requests', action='toggle_request_details', request_id=request.id )}">${details_state}</a> </div> @@ -217,7 +216,6 @@ %endif </div> %endif - ##</div> - <input type="hidden" name="request_id" value="${request.id}" /> + <input type="hidden" name="request_id" value="${request.id}" /> </form> </div> diff -r e66e1e99183c -r 98fa3b9cd980 test/functional/test_forms_and_requests.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/functional/test_forms_and_requests.py Thu Aug 20 10:46:52 2009 -0400 @@ -0,0 +1,212 @@ +import galaxy.model +from galaxy.model.orm import * +from base.twilltestcase import * + +not_logged_in_as_admin_security_msg = 'You must be logged in as an administrator to access this feature.' +logged_in_as_admin_security_msg = 'You must be an administrator to access this feature.' +not_logged_in_security_msg = 'You must be logged in to create/submit sequencing requests' +form_one_name = "Request Form" +form_two_name = "Sample Form" +request_type_name = 'Test Requestype' +sample_states = [ ( 'New', 'Sample entered into the system' ), + ( 'Received', 'Sample tube received' ), + ( 'Done', 'Sequence run complete' ) ] +address1 = dict( short_desc="Office", + name="James Bond", + institution="MI6" , + address1="MI6 Headquaters", + address2="", + city="London", + state="London", + postal_code="007", + country="United Kingdom", + phone="007-007-0007" ) + + +def get_latest_form(form_name): + fdc_list = galaxy.model.FormDefinitionCurrent.filter( galaxy.model.FormDefinitionCurrent.table.c.deleted==False )\ + .order_by( galaxy.model.FormDefinitionCurrent.table.c.create_time.desc() ) + for fdc in fdc_list: + if form_name == fdc.latest_form.name: + return fdc.latest_form + return None + + +class TestFormsAndRequests( TwillTestCase ): + def test_000_create_form( self ): + """Testing creating a new form and editing it""" + self.logout() + self.login( email='test@bx.psu.edu' ) + # create a form + global form_one_name + name = form_one_name + desc = "This is Form One's description" + self.create_form( name=name, desc=desc ) + self.home() + self.visit_page( 'forms/manage' ) + self.check_page_for_string( name ) + self.check_page_for_string( desc ) + # Get the form_definition object for later tests + form_one = galaxy.model.FormDefinition.filter( and_( galaxy.model.FormDefinition.table.c.name==name, + galaxy.model.FormDefinition.table.c.desc==desc ) ).all()[-1] + assert form_one is not None, 'Problem retrieving form named "%s" from the database' % name + # edit form & add few more fields + new_name = "Request Form (Renamed)" + new_desc = "This is Form One's Re-described" + self.edit_form( form_one.id, form_one.name, new_form_name=new_name, new_form_desc=new_desc ) + self.home() + self.visit_page( 'forms/manage' ) + self.check_page_for_string( new_name ) + self.check_page_for_string( new_desc ) + form_one_name = new_name + def test_005_add_form_fields( self ): + """Testing adding fields to a form definition""" + fields = [dict(name='Test field name one', + desc='Test field description one', + type='TextField', + required='required'), + dict(name='Test field name two', + desc='Test field description two', + type='AddressField', + required='optional')] + form_one = get_latest_form(form_one_name) + self.form_add_field(form_one.id, form_one.name, field_index=len(form_one.fields), fields=fields) + form_one_latest = get_latest_form(form_one_name) + assert len(form_one_latest.fields) == len(form_one.fields)+len(fields) +#This following test has been commented out as it is causing: +#TwillException: multiple matches to "remove_button" +# def test_010_remove_form_fields( self ): +# """Testing removing fields from a form definition""" +# form_one = get_latest_form(form_one_name) +# self.form_remove_field( form_one.id, form_one.name, 'Test field name one' ) +# form_one_latest = get_latest_form(form_one_name) +# assert len(form_one_latest.fields) == len(form_one.fields)-1 + def test_015_create_sample_form( self ): + """Testing creating another form (for samples)""" + global form_two_name + name = form_two_name + desc = "This is Form One's description" + self.create_form( name=name, desc=desc ) + self.home() + self.visit_page( 'forms/manage' ) + self.check_page_for_string( name ) + self.check_page_for_string( desc ) + def test_020_create_request_type( self ): + """Testing creating a new requestype""" + request_form = get_latest_form(form_one_name) + sample_form = get_latest_form(form_two_name) + self.create_request_type(request_type_name, "test request type", + str(request_form.id), str(sample_form.id), sample_states ) + global request_type + request_type = galaxy.model.RequestType.filter( and_( galaxy.model.RequestType.table.c.name==request_type_name ) ).all()[-1] + assert request_type is not None, 'Problem retrieving request type named "%s" from the database' % request_type_name + def test_025_create_address( self ): + """Testing address creation""" + #self.create_address( user_address1 ) + #self.check_page_for_string( 'Address <b>%s</b> has been added' % user_address1[ 'short_desc' ] ) + ## TODO: FIX HACK + ## the user address creation should be done as a test. + global user_address + user_address = galaxy.model.UserAddress() + user_address.user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test@bx.psu.edu' ).first() + user_address.desc = address1[ 'short_desc' ] + user_address.name = address1[ 'name' ] + user_address.institution = address1[ 'institution' ] + user_address.address = address1[ 'address1' ]+' '+address1[ 'address2' ] + user_address.city = address1[ 'city' ] + user_address.state = address1[ 'state' ] + user_address.postal_code = address1[ 'postal_code' ] + user_address.country = address1[ 'country' ] + user_address.phone = address1[ 'phone' ] + user_address.flush() + user_address.user.refresh() + def test_030_create_request( self ): + """Testing creating and submitting a request""" + # first create a library for the request so that it can be submitted later + lib_name = 'TestLib001' + self.create_library( lib_name, '' ) + self.visit_page( 'admin/browse_libraries' ) + self.check_page_for_string( lib_name ) + # Get the library object for later tests + global library_one + library_one = galaxy.model.Library.filter( and_( galaxy.model.Library.table.c.name==lib_name, + galaxy.model.Library.table.c.deleted==False ) ).first() + assert library_one is not None, 'Problem retrieving library named "%s" from the database' % lib_name + global admin_user + admin_user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test@bx.psu.edu' ).first() + assert admin_user is not None, 'Problem retrieving user with email "test@bx.psu.edu" from the database' + # Get the admin user's private role for later use + global admin_user_private_role + admin_user_private_role = None + for role in admin_user.all_roles(): + if role.name == admin_user.email and role.description == 'Private Role for %s' % admin_user.email: + admin_user_private_role = role + break + if not admin_user_private_role: + raise AssertionError( "Private role not found for user '%s'" % admin_user.email ) + # Set permissions on the library, sort for later testing + permissions_in = [ k for k, v in galaxy.model.Library.permitted_actions.items() ] + permissions_out = [] + # Role one members are: admin_user, regular_user1, regular_user3. Each of these users will be permitted to + # LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE for library items. + self.set_library_permissions( str( library_one.id ), library_one.name, str( admin_user_private_role.id ), permissions_in, permissions_out ) + # set field values + fields = ['field one value', 'field two value', str(user_address.id)] + # create the request + request_name, request_desc = 'Request One', 'Request One Description' + self.create_request(request_type.id, request_name, request_desc, library_one.id, fields) + self.check_page_for_string( request_name ) + self.check_page_for_string( request_desc ) + global request_one + request_one = galaxy.model.Request.filter( and_( galaxy.model.Request.table.c.name==request_name, + galaxy.model.Request.table.c.deleted==False ) ).first() + # check if the request's state is now set to 'unsubmitted' + assert request_one.state is not request_one.states.UNSUBMITTED, "The state of the request '%s' should be set to '%s'" % ( request_one.name, request_one.states.UNSUBMITTED ) + + # sample fields + samples = [ ( 'Sample One', [ 'S1 Field 0 Value' ] ), + ( 'Sample Two', [ 'S2 Field 0 Value' ] ) ] + # add samples to this request + self.add_samples( request_one.id, request_one.name, samples ) + for sample_name, fields in samples: + self.check_page_for_string( sample_name ) + self.check_page_for_string( 'Unsubmitted' ) + for field_value in fields: + self.check_page_for_string( field_value ) + # submit the request + self.submit_request( request_one.id, request_one.name ) + request_one.refresh() + # check if the request's state is now set to 'submitted' + assert request_one.state is not request_one.states.SUBMITTED, "The state of the request '%s' should be set to '%s'" % ( request_one.name, request_one.states.SUBMITTED ) + def test_035_request_lifecycle( self ): + """Testing request lifecycle as it goes through all the states""" + # goto admin manage requests page + self.home() + self.visit_page( 'requests_admin/list' ) + self.check_page_for_string( request_one.name ) + self.visit_url( "%s/requests_admin/list?sort=-create_time&operation=show_request&id=%s" \ + % ( self.url, self.security.encode_id( request_one.id ) )) + self.check_page_for_string( 'Sequencing Request "%s"' % request_one.name ) + # set bar codes for the samples + bar_codes = [ '1234567890', '0987654321' ] + self.add_bar_codes( request_one.id, request_one.name, bar_codes ) + self.check_page_for_string( 'Bar codes has been saved for this request' ) + # change the states of all the samples of this request + for sample in request_one.samples: + self.change_sample_state( sample.name, sample.id, request_type.states[1].id ) + self.check_page_for_string( request_type.states[1].name ) + self.check_page_for_string( request_type.states[1].desc ) + self.change_sample_state( sample.name, sample.id, request_type.states[2].id ) + self.check_page_for_string( request_type.states[2].name ) + self.check_page_for_string( request_type.states[2].desc ) + self.home() + request_one.refresh() + # check if the request's state is now set to 'complete' + assert request_one.state is not request_one.states.COMPLETE, "The state of the request '%s' should be set to '%s'" % ( request_one.name, request_one.states.COMPLETE ) + + + + + + + \ No newline at end of file