details: http://www.bx.psu.edu/hg/galaxy/rev/8d149264b777 changeset: 3122:8d149264b777 user: rc date: Wed Nov 25 14:06:28 2009 -0500 description: Request events & request rejection (resolves issue #221) - added request_events table - removed 'state' field in the request table - added 'new' & 'rejected' request states - color coded request states in the request grid Grids framework - added a confirm flag in grid operations which require confirmation before going through with operation diffstat: lib/galaxy/model/__init__.py | 35 +- lib/galaxy/model/mapping.py | 16 +- lib/galaxy/model/migrate/versions/0027_request_events.py | 94 ++++++ lib/galaxy/web/controllers/requests.py | 157 +++++++-- lib/galaxy/web/controllers/requests_admin.py | 299 +++++++++++++------ lib/galaxy/web/framework/helpers/grids.py | 4 +- templates/admin/requests/events.mako | 36 ++ templates/admin/requests/reject.mako | 42 ++ templates/admin/requests/show_request.mako | 13 +- templates/grid_base.mako | 6 +- templates/requests/events.mako | 39 ++ templates/requests/show_request.mako | 17 +- templates/sample/sample_events.mako | 43 +- test/base/twilltestcase.py | 9 +- test/functional/test_forms_and_requests.py | 30 +- 15 files changed, 651 insertions(+), 189 deletions(-) diffs (1296 lines): diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Tue Nov 24 14:53:19 2009 -0500 +++ b/lib/galaxy/model/__init__.py Wed Nov 25 14:06:28 2009 -0500 @@ -1260,11 +1260,12 @@ self.content = content class Request( object ): - states = Bunch( UNSUBMITTED = 'Unsubmitted', + states = Bunch( NEW = 'New', SUBMITTED = 'Submitted', + REJECTED = 'Rejected', COMPLETE = 'Complete') def __init__(self, name=None, desc=None, request_type=None, user=None, - form_values=None, library=None, folder=None, state=False): + form_values=None, library=None, folder=None): self.name = name self.desc = desc self.type = request_type @@ -1272,19 +1273,39 @@ self.user = user self.library = library self.folder = folder - self.state = state self.samples_list = [] + def state(self): + if self.events: + return self.events[0].state + return None + def last_comment(self): + if self.events: + if self.events[0].comment: + return self.events[0].comment + else: + return '' + return 'No comment' def has_sample(self, sample_name): for s in self.samples: if s.name == sample_name: return s return False + def unsubmitted(self): + return self.state() in [ self.states.REJECTED, self.states.NEW ] + def rejected(self): + return self.state() == self.states.REJECTED def submitted(self): - return self.state == self.states.SUBMITTED - def unsubmitted(self): - return self.state == self.states.UNSUBMITTED + return self.state() == self.states.SUBMITTED + def new(self): + return self.state() == self.states.NEW def complete(self): - return self.state == self.states.COMPLETE + return self.state() == self.states.COMPLETE + +class RequestEvent( object ): + def __init__(self, request=None, request_state=None, comment=''): + self.request = request + self.state = request_state + self.comment = comment class RequestType( object ): def __init__(self, name=None, desc=None, request_form=None, sample_form=None): diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py Tue Nov 24 14:53:19 2009 -0500 +++ b/lib/galaxy/model/mapping.py Wed Nov 25 14:06:28 2009 -0500 @@ -618,8 +618,15 @@ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ), Column( "library_id", Integer, ForeignKey( "library.id" ), index=True ), Column( "folder_id", Integer, ForeignKey( "library_folder.id" ), index=True ), + Column( "deleted", Boolean, index=True, default=False ) ) + +RequestEvent.table = Table('request_event', metadata, + Column( "id", Integer, primary_key=True), + Column( "create_time", DateTime, default=now ), + Column( "update_time", DateTime, default=now, onupdate=now ), + Column( "request_id", Integer, ForeignKey( "request.id" ), index=True ), Column( "state", TrimmedString( 255 ), index=True ), - Column( "deleted", Boolean, index=True, default=False ) ) + Column( "comment", TEXT ) ) Sample.table = Table('sample', metadata, Column( "id", Integer, primary_key=True ), @@ -768,9 +775,14 @@ folder=relation( LibraryFolder, primaryjoin=( Request.table.c.folder_id == LibraryFolder.table.c.id ) ), library=relation( Library, - primaryjoin=( Request.table.c.library_id == Library.table.c.id ) ) + primaryjoin=( Request.table.c.library_id == Library.table.c.id ) ), + events=relation( RequestEvent, backref="request", + order_by=desc(RequestEvent.table.c.update_time) ) ) ) +assign_mapper( context, RequestEvent, RequestEvent.table, + properties=None ) + assign_mapper( context, RequestType, RequestType.table, properties=dict( states=relation( SampleState, backref="request_type", diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/model/migrate/versions/0027_request_events.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/model/migrate/versions/0027_request_events.py Wed Nov 25 14:06:28 2009 -0500 @@ -0,0 +1,94 @@ +""" +This migration script adds the request_event table and +removes the state field in the request table +""" +from sqlalchemy import * +from sqlalchemy.orm import * +from sqlalchemy.exc import * +from migrate import * +from migrate.changeset import * + +import datetime +now = datetime.datetime.utcnow + +import sys, logging +log = logging.getLogger( __name__ ) +log.setLevel(logging.DEBUG) +handler = logging.StreamHandler( sys.stdout ) +format = "%(name)s %(levelname)s %(asctime)s %(message)s" +formatter = logging.Formatter( format ) +handler.setFormatter( formatter ) +log.addHandler( handler ) + +# Need our custom types, but don't import anything else from model +from galaxy.model.custom_types import * + +metadata = MetaData( migrate_engine ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +def display_migration_details(): + print "========================================" + print "This migration script adds the request_event table and" + print "removes the state field in the request table" + print "========================================" + +def localtimestamp(): + if migrate_engine.name == 'postgres' or migrate_engine.name == 'mysql': + return "LOCALTIMESTAMP" + elif migrate_engine.name == 'sqlite': + return "current_date || ' ' || current_time" + else: + raise Exception( 'Unable to convert data for unknown database type: %s' % db ) + +def nextval( table, col='id' ): + if migrate_engine.name == 'postgres': + return "nextval('%s_%s_seq')" % ( table, col ) + elif migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite': + return "null" + else: + raise Exception( 'Unable to convert data for unknown database type: %s' % migrate_engine.name ) + + +RequestEvent_table = Table('request_event', metadata, + Column( "id", Integer, primary_key=True), + Column( "create_time", DateTime, default=now ), + Column( "update_time", DateTime, default=now, onupdate=now ), + Column( "request_id", Integer, ForeignKey( "request.id" ), index=True ), + Column( "state", TrimmedString( 255 ), index=True ), + Column( "comment", TEXT ) ) + +def upgrade(): + display_migration_details() + # Load existing tables + metadata.reflect() + # Add new request_event table + try: + RequestEvent_table.create() + except Exception, e: + log.debug( "Creating request_event table failed: %s" % str( e ) ) + # move the current state of all existing requests to the request_event table + cmd = \ + "INSERT INTO request_event " + \ + "SELECT %s AS id," + \ + "%s AS create_time," + \ + "%s AS update_time," + \ + "request.id AS request_id," + \ + "request.state AS state " + \ + "FROM request;" + cmd = cmd % ( nextval('request_event'), localtimestamp(), localtimestamp() ) + db_session.execute( cmd ) + + # Delete the state column + try: + Request_table = Table( "request", metadata, autoload=True ) + except NoSuchTableError: + Request_table = None + log.debug( "Failed loading table request" ) + if Request_table: + try: + Request_table.c.state.drop() + except Exception, e: + log.debug( "Deleting column 'state' to request table failed: %s" % ( str( e ) ) ) + +def downgrade(): + pass \ No newline at end of file diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/web/controllers/requests.py --- a/lib/galaxy/web/controllers/requests.py Tue Nov 24 14:53:19 2009 -0500 +++ b/lib/galaxy/web/controllers/requests.py Wed Nov 25 14:06:28 2009 -0500 @@ -28,27 +28,57 @@ return request.type.name class LastUpdateColumn( grids.TextColumn ): def get_value(self, trans, grid, request): - return request.update_time + delta = datetime.utcnow() - request.update_time + if delta > timedelta( minutes=60 ): + last_update = '%s hours' % int( delta.seconds / 60 / 60 ) + else: + last_update = '%s minutes' % int( delta.seconds / 60 ) + return last_update class StateColumn( grids.GridColumn ): + def __init__( self, col_name, key, model_class, event_class, filterable, link ): + grids.GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable, link=link) + self.event_class = event_class + def get_value(self, trans, grid, request): + if request.state() == request.states.REJECTED: + return '<div class="count-box state-color-error">%s</div>' % request.state() + elif request.state() == request.states.NEW: + return '<div class="count-box state-color-queued">%s</div>' % request.state() + elif request.state() == request.states.SUBMITTED: + return '<div class="count-box state-color-running">%s</div>' % request.state() + elif request.state() == request.states.COMPLETE: + return '<div class="count-box state-color-ok">%s</div>' % request.state() + return request.state() def filter( self, db_session, query, column_filter ): """ Modify query to filter request by state. """ if column_filter == "All": return query if column_filter: - query = query.filter( model.Request.state == column_filter ) - return query + # select r.id, r.name, re.id, re.state + # from request as r, request_event as re + # where re.request_id=r.id and re.state='Complete' and re.create_time in + # (select MAX( create_time) + # from request_event + # group by request_id) + q = query.join(self.event_class.table)\ + .filter( self.model_class.table.c.id==self.event_class.table.c.request_id )\ + .filter( self.event_class.table.c.state==column_filter )\ + .filter( self.event_class.table.c.id.in_(select(columns=[func.max(self.event_class.table.c.id)], + from_obj=self.event_class.table, + group_by=self.event_class.table.c.request_id))) + return q def get_accepted_filters( self ): - """ Returns a list of accepted filters for this column. """ - accepted_filter_labels_and_vals = [ model.Request.states.UNSUBMITTED, - model.Request.states.SUBMITTED, - model.Request.states.COMPLETE, - "All"] - accepted_filters = [] - for val in accepted_filter_labels_and_vals: - label = val.lower() - args = { self.key: val } - accepted_filters.append( grids.GridColumnFilter( label, args) ) - return accepted_filters + """ Returns a list of accepted filters for this column. """ + accepted_filter_labels_and_vals = [ model.Request.states.NEW, + model.Request.states.REJECTED, + model.Request.states.SUBMITTED, + model.Request.states.COMPLETE, + "All"] + accepted_filters = [] + for val in accepted_filter_labels_and_vals: + label = val.lower() + args = { self.key: val } + accepted_filters.append( grids.GridColumnFilter( label, args) ) + return accepted_filters class DeletedColumn( grids.GridColumn ): def get_accepted_filters( self ): """ Returns a list of accepted filters for this column. """ @@ -66,7 +96,7 @@ num_rows_per_page = 50 preserve_state = True use_paging = True - default_filter = dict( deleted="False", state=model.Request.states.UNSUBMITTED) + default_filter = dict( deleted="False", state=model.Request.states.NEW) columns = [ NameColumn( "Name", key="name", @@ -83,23 +113,27 @@ TypeColumn( "Type" ), LastUpdateColumn( "Last update", format=time_ago ), - StateColumn( "State", - key='state', - filterable="advanced"), DeletedColumn( "Deleted", key="deleted", - visible=True, - filterable="advanced" ) + visible=False, + filterable="advanced" ), + StateColumn( "State", + model_class=model.Request, + event_class=model.RequestEvent, + key='state', + filterable="advanced", + link=( lambda item: iff( item.deleted, None, dict( operation="events", id=item.id ) ) ) ) ] columns.append( grids.MulticolFilterColumn( "Search", - cols_to_filter=[ columns[0], columns[1] ], + cols_to_filter=[ columns[0], columns[1], columns[6] ], key="free-text-search", visible=False, filterable="standard" ) ) operations = [ - grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ) ), + grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ), + confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." ), grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), - grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted and item.new() ) ), grids.GridOperation( "Undelete", allow_multiple=True, condition=( lambda item: item.deleted ) ) ] @@ -145,9 +179,23 @@ return self.__undelete_request( trans, **kwd ) elif operation == "edit": return self.__edit_request( trans, **kwd ) + elif operation == "events": + return self.__request_events( trans, **kwd ) + # if there are one or more requests that has been rejected by the admin + # recently, then show a msg as a reminder to the user + rlist = trans.sa_session.query( trans.app.model.Request ) \ + .filter( trans.app.model.Request.table.c.deleted==False ) \ + .filter( trans.app.model.Request.table.c.user_id==trans.user.id ) + rejected = 0 + for r in rlist: + if r.rejected(): + rejected = rejected + 1 + if rejected: + kwd['status'] = 'warning' + kwd['message'] = "%d requests (highlighted in red) were rejected, click on the request name for details." \ + % rejected # Render the list view return self.request_grid( trans, **kwd ) - def __show_request(self, trans, **kwd): params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) @@ -172,6 +220,28 @@ sample_copy=self.__copy_sample(current_samples), details='hide', edit_mode='False', msg=msg, messagetype=messagetype ) + def __request_events(self, trans, **kwd): + try: + request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) ) + except: + msg = "Invalid request ID" + log.warn( msg ) + return trans.response.send_redirect( web.url_for( controller='requests', + action='list', + status='error', + message=msg, + **kwd) ) + events_list = [] + all_events = request.events + for event in all_events: + delta = datetime.utcnow() - event.update_time + if delta > timedelta( minutes=60 ): + last_update = '%s hours' % int( delta.seconds / 60 / 60 ) + else: + last_update = '%s minutes' % int( delta.seconds / 60 ) + events_list.append((event.state, last_update, event.comment)) + return trans.fill_template( '/requests/events.mako', + events_list=events_list, request=request) def request_details(self, trans, id): ''' Shows the request details @@ -187,7 +257,7 @@ value=request.type.name, helptext='')) request_details.append(dict(label='State', - value=request.state, + value=request.state(), helptext='')) request_details.append(dict(label='Date created', value=request.create_time, @@ -366,9 +436,9 @@ trans.sa_session.add( sample ) trans.sa_session.flush() return trans.response.send_redirect( web.url_for( controller='requests', - action='list', - operation='show_request', - id=trans.security.encode_id(request.id)) ) + action='list', + operation='show_request', + id=trans.security.encode_id(request.id)) ) elif params.get('edit_samples_button', False) == 'Edit samples': edit_mode = 'True' return trans.fill_template( '/requests/show_request.mako', @@ -700,10 +770,15 @@ if not request: request = trans.app.model.Request(name, desc, request_type, trans.user, form_values, - library=library, folder=folder, - state=trans.app.model.Request.states.UNSUBMITTED) + library=library, folder=folder) trans.sa_session.add( request ) trans.sa_session.flush() + trans.sa_session.refresh( request ) + # create an event with state 'New' for this new request + comments = "Request created." + event = trans.app.model.RequestEvent(request, request.states.NEW, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() else: request.name = name request.desc = desc @@ -712,7 +787,6 @@ request.values = form_values request.library = library request.folder = folder - request.state = trans.app.model.Request.states.UNSUBMITTED trans.sa_session.add( request ) trans.sa_session.flush() return request @@ -731,7 +805,7 @@ message="Invalid request ID", **kwd) ) if params.get('show', False) == 'True': - return self.__edit_request(trans, **kwd) + return self.__edit_request(trans, id=trans.security.encode_id(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.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) ) @@ -760,7 +834,7 @@ messagetype='done', **new_kwd) ) elif params.get('refresh', False) == 'true': - return self.__edit_request(trans, **kwd) + return self.__edit_request(trans, id=trans.security.encode_id(request.id), **kwd) def __edit_request(self, trans, **kwd): try: @@ -819,7 +893,7 @@ message=msg, **kwd) ) # a request cannot be deleted once its submitted - if not request.unsubmitted(): + if not request.new(): delete_failed.append(request.name) else: request.deleted = True @@ -870,21 +944,22 @@ msg = self.__validate(trans, request) if msg: return trans.response.send_redirect( web.url_for( controller='requests', - action='edit', + action='list', + operation='edit', messagetype = 'error', msg=msg, - request_id=request.id, - show='True') ) + id=trans.security.encode_id(request.id) )) + # change the request state to 'Submitted' + comments = "Request moved to 'Submitted' state." + event = trans.app.model.RequestEvent(request, request.states.SUBMITTED, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() # 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') trans.sa_session.add( event ) trans.sa_session.flush() - # change request's submitted field - request.state = request.states.SUBMITTED - trans.sa_session.add( request ) - trans.sa_session.flush() return trans.response.send_redirect( web.url_for( controller='requests', action='list', id=trans.security.encode_id(request.id), diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/web/controllers/requests_admin.py --- a/lib/galaxy/web/controllers/requests_admin.py Tue Nov 24 14:53:19 2009 -0500 +++ b/lib/galaxy/web/controllers/requests_admin.py Wed Nov 25 14:06:28 2009 -0500 @@ -8,6 +8,8 @@ from galaxy.web.form_builder import * from datetime import datetime, timedelta from galaxy.web.controllers.forms import get_all_forms +from sqlalchemy.sql.expression import func, and_ +from sqlalchemy.sql import select log = logging.getLogger( __name__ ) @@ -31,27 +33,58 @@ return request.type.name class LastUpdateColumn( grids.TextColumn ): def get_value(self, trans, grid, request): - return request.update_time + delta = datetime.utcnow() - request.update_time + if delta > timedelta( minutes=60 ): + last_update = '%s hours' % int( delta.seconds / 60 / 60 ) + else: + last_update = '%s minutes' % int( delta.seconds / 60 ) + return last_update class StateColumn( grids.GridColumn ): + def __init__( self, col_name, key, model_class, event_class, filterable, link ): + grids.GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable, link=link) + self.event_class = event_class + def get_value(self, trans, grid, request): + if request.state() == request.states.REJECTED: + return '<div class="count-box state-color-error">%s</div>' % request.state() + elif request.state() == request.states.NEW: + return '<div class="count-box state-color-queued">%s</div>' % request.state() + elif request.state() == request.states.SUBMITTED: + return '<div class="count-box state-color-running">%s</div>' % request.state() + elif request.state() == request.states.COMPLETE: + return '<div class="count-box state-color-ok">%s</div>' % request.state() + return request.state() def filter( self, db_session, query, column_filter ): """ Modify query to filter request by state. """ if column_filter == "All": return query if column_filter: - query = query.filter( model.Request.state == column_filter ) - return query + # select r.id, r.name, re.id, re.state + # from request as r, request_event as re + # where re.request_id=r.id and re.state='Complete' and re.create_time in + # (select MAX( create_time) + # from request_event + # group by request_id) + q = query.join(self.event_class.table)\ + .filter( self.model_class.table.c.id==self.event_class.table.c.request_id )\ + .filter( self.event_class.table.c.state==column_filter )\ + .filter( self.event_class.table.c.id.in_(select(columns=[func.max(self.event_class.table.c.id)], + from_obj=self.event_class.table, + group_by=self.event_class.table.c.request_id))) + #print column_filter, q + return q def get_accepted_filters( self ): - """ Returns a list of accepted filters for this column. """ - accepted_filter_labels_and_vals = [ model.Request.states.UNSUBMITTED, - model.Request.states.SUBMITTED, - model.Request.states.COMPLETE, - "All"] - accepted_filters = [] - for val in accepted_filter_labels_and_vals: - label = val.lower() - args = { self.key: val } - accepted_filters.append( grids.GridColumnFilter( label, args) ) - return accepted_filters + """ Returns a list of accepted filters for this column. """ + accepted_filter_labels_and_vals = [ model.Request.states.NEW, + model.Request.states.REJECTED, + model.Request.states.SUBMITTED, + model.Request.states.COMPLETE, + "All"] + accepted_filters = [] + for val in accepted_filter_labels_and_vals: + label = val.lower() + args = { self.key: val } + accepted_filters.append( grids.GridColumnFilter( label, args) ) + return accepted_filters class UserColumn( grids.TextColumn ): def get_value(self, trans, grid, request): return request.user.email @@ -86,20 +119,25 @@ filterable="advanced" ), SamplesColumn( "Sample(s)", link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ), - TypeColumn( "Type" ), + TypeColumn( "Type", + link=( lambda item: iff( item.deleted, None, dict( operation="view_type", id=item.type.id ) ) ), ), LastUpdateColumn( "Last update", format=time_ago ), - StateColumn( "State", - key='state', - filterable="advanced"), - UserColumn( "User", - key='user.email', - model_class=model.Request, - filterable="advanced" ), DeletedColumn( "Deleted", key="deleted", - visible=True, - filterable="advanced" ) + visible=False, + filterable="advanced" ), + StateColumn( "State", + model_class=model.Request, + event_class=model.RequestEvent, + key='state', + filterable="advanced", + link=( lambda item: iff( item.deleted, None, dict( operation="events", id=item.id ) ) ), + ), + UserColumn( "User", + #key='user.email', + model_class=model.Request) + ] columns.append( grids.MulticolFilterColumn( "Search", cols_to_filter=[ columns[0], columns[1], columns[6] ], @@ -107,10 +145,11 @@ visible=False, filterable="standard" ) ) operations = [ - grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ) ), + grids.GridOperation( "Submit", allow_multiple=False, condition=( lambda item: not item.deleted and item.unsubmitted() and item.samples ), + confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." ), grids.GridOperation( "Edit", allow_multiple=False, condition=( lambda item: not item.deleted ) ), grids.GridOperation( "Reject", allow_multiple=False, condition=( lambda item: not item.deleted and item.submitted() ) ), - grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted and item.unsubmitted() ) ), + grids.GridOperation( "Delete", allow_multiple=True, condition=( lambda item: not item.deleted and item.new() ) ), grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ), ] global_actions = [ @@ -227,6 +266,11 @@ return self.__edit_request( trans, **kwd ) elif operation == "reject": return self.__reject_request( trans, **kwd ) + elif operation == "events": + return self.__request_events( trans, **kwd ) + elif operation == "view_type": + return self.__view_request_type( trans, **kwd ) + # Render the grid view return self.request_grid( trans, **kwd ) def __show_request(self, trans, **kwd): @@ -253,7 +297,52 @@ sample_copy=self.__copy_sample(current_samples), details='hide', edit_mode='False', msg=msg, messagetype=messagetype ) - + @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.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) ) + if params.get('show', False) == 'True': + return self.__edit_request(trans, id=trans.security.encode_id(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.sa_session.query( 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_admin', + 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_admin', + 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_admin', + action='show_request', + msg=msg , + messagetype='done', + **new_kwd) ) + elif params.get('refresh', False) == 'true': + return self.__edit_request(trans, id=trans.security.encode_id(request.id), **kwd) + def __edit_request(self, trans, **kwd): try: request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) ) @@ -311,7 +400,7 @@ message=msg, **kwd) ) # a request cannot be deleted once its submitted - if not request.unsubmitted(): + if not request.new(): delete_failed.append(request.name) else: request.deleted = True @@ -362,18 +451,24 @@ msg = self.__validate(trans, request) if msg: return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='edit', + action='list', + operation='edit', messagetype = 'error', msg=msg, - request_id=request.id, - show='True') ) - # get the new state + id=trans.security.encode_id(request.id) ) ) + # change the request state to 'Submitted' + if request.user.email is not trans.user: + comments = "Request moved to 'Submitted' state by admin (%s) on behalf of %s." % (trans.user.email, request.user.email) + else: + comments = "" + event = trans.app.model.RequestEvent(request, request.states.SUBMITTED, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() + # change the state of each of the samples of thus request new_state = request.type.states[0] for s in request.samples: event = trans.app.model.SampleEvent(s, new_state, 'Samples submitted to the system') trans.sa_session.add( event ) - # change request's submitted field - request.state = request.states.SUBMITTED trans.sa_session.add( request ) trans.sa_session.flush() return trans.response.send_redirect( web.url_for( controller='requests_admin', @@ -393,15 +488,64 @@ status='error', message=msg, **kwd) ) - # change request's submitted field - request.state = request.states.UNSUBMITTED - trans.sa_session.add( request ) + return trans.fill_template( '/admin/requests/reject.mako', + request=request) + @web.expose + @web.require_admin + def reject(self, trans, **kwd): + params = util.Params( kwd ) + if params.get('cancel_reject_button', False): + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='list', + operation='show_request', + id=kwd['id'])) + try: + request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['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) ) + # validate + if not params.get('comment', ''): + return trans.fill_template( '/admin/requests/reject.mako', + request=request, messagetype='error', + msg='A comment is required for rejecting a request.') + # create an event with state 'Rejected' for this request + comments = util.restore_text( params.comment ) + event = trans.app.model.RequestEvent(request, request.states.REJECTED, comments) + trans.sa_session.add( event ) trans.sa_session.flush() return trans.response.send_redirect( web.url_for( controller='requests_admin', action='list', status='done', - message='The request <b>%s</b> is now unsubmitted.' % request.name - ) ) + message='Request <b>%s</b> has been rejected.' % request.name) ) + + def __request_events(self, trans, **kwd): + try: + request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['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) ) + events_list = [] + all_events = request.events + for event in all_events: + delta = datetime.utcnow() - event.update_time + if delta > timedelta( minutes=60 ): + last_update = '%s hours' % int( delta.seconds / 60 / 60 ) + else: + last_update = '%s minutes' % int( delta.seconds / 60 ) + events_list.append((event.state, last_update, event.comment)) + return trans.fill_template( '/admin/requests/events.mako', + events_list=events_list, request=request) # #---- Request Creation ---------------------------------------------------------- # @@ -732,9 +876,18 @@ if not request: request = trans.app.model.Request(name, desc, request_type, user, form_values, - library=library, folder=folder, - state=trans.app.model.Request.states.UNSUBMITTED) + library=library, folder=folder) trans.sa_session.add( request ) + trans.sa_session.flush() + trans.sa_session.refresh( request ) + # create an event with state 'New' for this new request + if request.user.email is not trans.user: + comments = "Request created by admin (%s) on behalf of %s." % (trans.user.email, request.user.email) + else: + comments = "Request created." + event = trans.app.model.RequestEvent(request, request.states.NEW, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() else: request.name = name request.desc = desc @@ -744,58 +897,14 @@ request.library = library request.folder = folder trans.sa_session.add( request ) - trans.sa_session.flush() + trans.sa_session.flush() + return request # -#---- Request Editing ---------------------------------------------------------- +#---- Request Page ---------------------------------------------------------- # - @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.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) ) - 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.sa_session.query( 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_admin', - 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_admin', - 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_admin', - action='show_request', - msg=msg , - messagetype='done', - **new_kwd) ) - elif params.get('refresh', False) == 'true': - return self.__edit_request(trans, request.id, **kwd) def __update_samples(self, request, **kwd): ''' This method retrieves all the user entered sample information and @@ -1013,7 +1122,7 @@ value=request.type.name, helptext='')) request_details.append(dict(label='State', - value=request.state, + value=request.state(), helptext='')) request_details.append(dict(label='Date created', value=request.create_time, @@ -1167,11 +1276,13 @@ if s.current_state().id != request.type.states[-1].id: complete = False if complete: - request.state = request.states.COMPLETE - else: - request.state = request.states.SUBMITTED - trans.sa_session.add( request ) - trans.sa_session.flush() + # change the request state to 'Complete' + comments = "All samples of this request are in the last sample state (%s)." % request.type.states[-1].name + event = trans.app.model.RequestEvent(request, request.states.COMPLETE, comments) + trans.sa_session.add( event ) + trans.sa_session.flush() +# trans.sa_session.add( request ) +# trans.sa_session.flush() def change_state(self, trans, sample): possible_states = sample.request.type.states curr_state = sample.current_state() diff -r 5761948422a8 -r 8d149264b777 lib/galaxy/web/framework/helpers/grids.py --- a/lib/galaxy/web/framework/helpers/grids.py Tue Nov 24 14:53:19 2009 -0500 +++ b/lib/galaxy/web/framework/helpers/grids.py Wed Nov 25 14:06:28 2009 -0500 @@ -402,7 +402,7 @@ return query.filter( complete_filter ) class GridOperation( object ): - def __init__( self, label, key=None, condition=None, allow_multiple=True, allow_popup=True, target=None, url_args=None, async_compatible=False ): + def __init__( self, label, key=None, condition=None, allow_multiple=True, allow_popup=True, target=None, url_args=None, async_compatible=False, confirm=None ): self.label = label self.key = key self.allow_multiple = allow_multiple @@ -411,6 +411,8 @@ self.target = target self.url_args = url_args self.async_compatible = async_compatible + # if 'confirm' is set, then ask before completing the operation + self.confirm = confirm def get_url_args( self, item ): if self.url_args: temp = dict( self.url_args ) diff -r 5761948422a8 -r 8d149264b777 templates/admin/requests/events.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/admin/requests/events.mako Wed Nov 25 14:06:28 2009 -0500 @@ -0,0 +1,36 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +<h2>History of Sequencing Request "${request.name}"</h2> +<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> +</ul> +<h3>User: ${request.user.email}</h3> + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +<div class="toolForm"> + <table class="grid"> + <thead> + <tr> + <th>State</th> + <th>Last Update</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> + </tr> + %endfor + </tbody> + </table> +</div> diff -r 5761948422a8 -r 8d149264b777 templates/admin/requests/reject.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/admin/requests/reject.mako Wed Nov 25 14:06:28 2009 -0500 @@ -0,0 +1,42 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +<h2>Reject Sequencing Request "${request.name}"</h2> +<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', operation='events', id=trans.security.encode_id(request.id) )}"> + <span>Events</span></a> + </li> +</ul> +<h3>User: ${request.user.email}</h3> + + + +<div class="toolForm"> + <div class="toolFormTitle">Reject request</div> + <form name="event" action="${h.url_for( controller='requests_admin', action='reject', 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>. + </div> + <div class="form-row"> + <label>Comments</label> + <textarea name="comment" rows="5" cols="40"></textarea> + <div class="toolParamHelp" style="clear: both;"> + Required + </div> + </div> + <div class="form-row"> + <input type="submit" name="reject_button" value="Reject"/> + <input type="submit" name="cancel_reject_button" value="Cancel"/> + </div> + </form> + </div> +</div> \ No newline at end of file diff -r 5761948422a8 -r 8d149264b777 templates/admin/requests/show_request.mako --- a/templates/admin/requests/show_request.mako Tue Nov 24 14:53:19 2009 -0500 +++ b/templates/admin/requests/show_request.mako Wed Nov 25 14:06:28 2009 -0500 @@ -5,11 +5,16 @@ ${render_msg( msg, messagetype )} %endif +%if request.rejected(): + ${render_msg( "Reason for rejection: "+request.last_comment(), "warning" )} +%endif + <div class="grid-header"> <h2>Sequencing Request "${request.name}"</h2> </div> <ul class="manage-table-actions"> + %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='list', operation='Submit', id=trans.security.encode_id(request.id) )}"> @@ -28,6 +33,10 @@ <span>Bar codes</span></a> </li> %endif + <li> + <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='events', id=trans.security.encode_id(request.id) )}"> + <span>History</span></a> + </li> </ul> @@ -82,7 +91,7 @@ %if grid_index == 0: <td>${sample.bar_code}</td> <td> - %if sample.request.unsubmitted(): + %if sample.request.new(): Unsubmitted %else: <a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a> @@ -117,6 +126,8 @@ %else: <i>None</i> %endif + %elif rd['label'] == 'State': + <a href="${h.url_for( controller='requests_admin', action='list', operation='events', id=trans.security.encode_id(request.id) )}">${rd['value']}</a> %else: ${rd['value']} %endif diff -r 5761948422a8 -r 8d149264b777 templates/grid_base.mako --- a/templates/grid_base.mako Tue Nov 24 14:53:19 2009 -0500 +++ b/templates/grid_base.mako Wed Nov 25 14:06:28 2009 -0500 @@ -860,7 +860,11 @@ if operation.target: target = "target='" + operation.target + "'" %> - <a class="action-button" ${target} href="${ url( **operation.get_url_args( item ) ) }">${operation.label}</a> + %if operation.confirm: + <a class="action-button" ${target} confirm="${operation.confirm}" href="${ url( **operation.get_url_args( item ) ) }">${operation.label}</a> + %else: + <a class="action-button" ${target} href="${ url( **operation.get_url_args( item ) ) }">${operation.label}</a> + %endif %endif %endfor </div> diff -r 5761948422a8 -r 8d149264b777 templates/requests/events.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/requests/events.mako Wed Nov 25 14:06:28 2009 -0500 @@ -0,0 +1,39 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +<h2>History of Sequencing Request "${request.name}"</h2> +<ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='requests', 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', action='list')}"> + <span>Browse all requests</span></a> + </li> +</ul> + +%if msg: + ${render_msg( msg, messagetype )} +%endif + +<div class="toolForm"> + <table class="grid"> + <thead> + <tr> + <th>State</th> + <th>Last Update</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> + </tr> + %endfor + </tbody> + </table> +</div> diff -r 5761948422a8 -r 8d149264b777 templates/requests/show_request.mako --- a/templates/requests/show_request.mako Tue Nov 24 14:53:19 2009 -0500 +++ b/templates/requests/show_request.mako Wed Nov 25 14:06:28 2009 -0500 @@ -6,6 +6,9 @@ ${render_msg( msg, messagetype )} %endif +%if request.rejected(): + ${render_msg( "Reason for rejection: "+request.last_comment(), "warning" )} +%endif <div class="grid-header"> <h2>Sequencing Request "${request.name}"</h2> @@ -19,6 +22,10 @@ </li> %endif <li> + <a class="action-button" href="${h.url_for( controller='requests', action='list', operation='events', id=trans.security.encode_id(request.id) )}"> + <span>History</span></a> + </li> + <li> <a class="action-button" href="${h.url_for( controller='requests', action='list')}"> <span>Browse requests</span></a> </li> @@ -73,7 +80,7 @@ </td> %if grid_index == 0: <td> - %if sample.request.unsubmitted(): + %if sample.request.new(): Unsubmitted %else: <a href="${h.url_for( controller='requests', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a> @@ -105,9 +112,11 @@ %if rd['label'] == 'Data library': %if rd['value']: <a href="${h.url_for( controller='library', action='browse_library', obj_id=request.library.id )}">${rd['value']}</a> - %else: - <i>None</i> - %endif + %elif rd['label'] == 'State': + <a href="${h.url_for( controller='requests', action='list', operation='events', id=trans.security.encode_id(request.id) )}">${rd['value']}</a> + %else: + <i>None</i> + %endif %else: ${rd['value']} %endif diff -r 5761948422a8 -r 8d149264b777 templates/sample/sample_events.mako --- a/templates/sample/sample_events.mako Tue Nov 24 14:53:19 2009 -0500 +++ b/templates/sample/sample_events.mako Wed Nov 25 14:06:28 2009 -0500 @@ -21,24 +21,25 @@ ${render_msg( msg, messagetype )} %endif - -<table class="grid"> - <thead> - <tr> - <th>State</th> - <th>Description</th> - <th>Updated</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> \ No newline at end of file +<div class="toolForm"> + <table class="grid"> + <thead> + <tr> + <th>State</th> + <th>Description</th> + <th>Updated</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> \ No newline at end of file diff -r 5761948422a8 -r 8d149264b777 test/base/twilltestcase.py --- a/test/base/twilltestcase.py Tue Nov 24 14:53:19 2009 -0500 +++ b/test/base/twilltestcase.py Wed Nov 25 14:06:28 2009 -0500 @@ -1298,10 +1298,15 @@ self.home() self.visit_url( "%s/requests_admin/list?operation=Submit&id=%s" % ( self.url, self.security.encode_id( request_id ) )) self.check_page_for_string( 'The request <b>%s</b> has been submitted.' % request_name ) - def reject_request( self, request_id, request_name ): + def reject_request( self, request_id, request_name, comment ): self.home() self.visit_url( "%s/requests_admin/list?operation=Reject&id=%s" % ( self.url, self.security.encode_id( request_id ) )) - self.check_page_for_string( 'The request <b>%s</b> is now unsubmitted.' % request_name ) + self.check_page_for_string( 'Reject Sequencing Request "%s"' % request_name ) + tc.fv( "1", "comment", comment ) + tc.submit( "reject_button" ) + self.check_page_for_string( 'Request <b>%s</b> has been rejected.' % request_name ) + self.visit_url( "%s/requests/list?sort=-create_time&operation=show_request&id=%s" % ( self.url, self.security.encode_id( request_id ) )) + self.check_page_for_string( comment ) def add_bar_codes( self, request_id, request_name, bar_codes ): self.home() self.visit_url( "%s/requests_admin/bar_codes?request_id=%i" % (self.url, request_id) ) diff -r 5761948422a8 -r 8d149264b777 test/functional/test_forms_and_requests.py --- a/test/functional/test_forms_and_requests.py Tue Nov 24 14:53:19 2009 -0500 +++ b/test/functional/test_forms_and_requests.py Wed Nov 25 14:06:28 2009 -0500 @@ -194,9 +194,9 @@ .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 ) + # check if the request's state is now set to 'new' + assert request_one.state is not request_one.states.NEW, "The state of the request '%s' should be set to '%s'" \ + % ( request_one.name, request_one.states.NEW ) # sample fields samples = [ ( 'Sample One', [ 'S1 Field 0 Value' ] ), ( 'Sample Two', [ 'S2 Field 0 Value' ] ) ] @@ -207,8 +207,8 @@ self.edit_request(request_one.id, request_one.name, request_one.name+' (Renamed)', request_one.desc+' (Re-described)', library_one.id, folder_one.id, fields) sa_session.refresh( request_one ) - # check if the request is showing in the 'unsubmitted' filter - self.check_request_grid(state='Unsubmitted', request_name=request_one.name) + # check if the request is showing in the 'new' filter + self.check_request_grid(state='New', request_name=request_one.name) # submit the request self.submit_request( request_one.id, request_one.name ) sa_session.refresh( request_one ) @@ -257,11 +257,11 @@ .filter( and_( galaxy.model.Request.table.c.name==request_name, galaxy.model.Request.table.c.deleted==False ) ) \ .first() - # check if the request is showing in the 'unsubmitted' filter - self.check_request_admin_grid(state='Unsubmitted', request_name=request_two.name) - # check if the request's state is now set to 'unsubmitted' - assert request_two.state is not request_two.states.UNSUBMITTED, "The state of the request '%s' should be set to '%s'" \ - % ( request_two.name, request_two.states.UNSUBMITTED ) + # check if the request is showing in the 'new' filter + self.check_request_admin_grid(state='New', request_name=request_two.name) + # check if the request's state is now set to 'new' + assert request_two.state is not request_two.states.NEW, "The state of the request '%s' should be set to '%s'" \ + % ( request_two.name, request_two.states.NEW ) # sample fields samples = [ ( 'Sample One', [ 'S1 Field 0 Value' ] ), ( 'Sample Two', [ 'S2 Field 0 Value' ] ) ] @@ -282,10 +282,10 @@ '''Testing rejecting a request''' self.logout() self.login( email='test@bx.psu.edu' ) - self.reject_request( request_two.id, request_two.name ) + self.reject_request( request_two.id, request_two.name, "Rejection test comment" ) sa_session.refresh( request_two ) - # check if the request is showing in the 'unsubmitted' filter - self.check_request_admin_grid(state='Unsubmitted', request_name=request_two.name) + # check if the request is showing in the 'rejected' filter + self.check_request_admin_grid(state='Rejected', request_name=request_two.name) # check if the request's state is now set to 'submitted' - assert request_two.state is not request_two.states.UNSUBMITTED, "The state of the request '%s' should be set to '%s'" \ - % ( request_two.name, request_two.states.UNSUBMITTED ) + assert request_two.state is not request_two.states.REJECTED, "The state of the request '%s' should be set to '%s'" \ + % ( request_two.name, request_two.states.REJECTED )