galaxy-dev
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- 10009 discussions
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/6e742ffb16a5
changeset: 3134:6e742ffb16a5
user: jeremy goecks <jeremy.goecks at emory.edu>
date: Tue Dec 01 11:07:20 2009 -0500
description:
Improved loading state for AJAXed grids: when grid is loading, gray out table and prevent further user actions.
diffstat:
templates/grid_base.mako | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diffs (47 lines):
diff -r e75b55cc9e08 -r 6e742ffb16a5 templates/grid_base.mako
--- a/templates/grid_base.mako Tue Dec 01 09:53:36 2009 -0500
+++ b/templates/grid_base.mako Tue Dec 01 11:07:20 2009 -0500
@@ -601,6 +601,7 @@
// If there's an operation in the args, do POST; otherwise, do GET.
var operation = url_args['operation'];
var method = (operation != null && operation != undefined ? "POST" : "GET" );
+ $('.loading-elt-overlay').show(); // Show overlay to indicate loading and prevent user actions.
$.ajax({
type: method,
url: "${h.url_for()}",
@@ -660,6 +661,9 @@
}
}
+ // Hide loading overlay.
+ $('.loading-elt-overlay').hide();
+
// Show message if there is one.
var message = $.trim( parsed_response_text[2] );
if (message != "")
@@ -711,6 +715,15 @@
.gray-background {
background-color: #DDDDDD;
}
+ .loading-elt-overlay {
+ background-color : white;
+ opacity : 0.5;
+ width : 100%;
+ height : 85%;
+ z-index : 14000;
+ position : absolute;
+ display: none;
+ }
</style>
</%def>
@@ -750,7 +763,8 @@
## Render grid.
<%def name="render_grid_table()">
<form action="${url()}" method="post" onsubmit="return false;">
- <table class="grid">
+ <div class='loading-elt-overlay'></div>
+ <table id='grid-table' class="grid">
<thead id="grid-table-header">
<tr>
<th></th>
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/eb317734e391
changeset: 3135:eb317734e391
user: guru
date: Tue Dec 01 11:49:07 2009 -0500
description:
Adding back 'wiggle to interval' converter
diffstat:
datatypes_conf.xml.sample | 1 +
lib/galaxy/datatypes/converters/wiggle_to_simple_converter.py | 44 +++++++
lib/galaxy/datatypes/converters/wiggle_to_simple_converter.xml | 11 +
test-data/3.wig | 37 ++++++
test-data/3_wig.bed | 26 ++++
tool_conf.xml.main | 1 +
tool_conf.xml.sample | 1 +
tools/filters/wiggle_to_simple.py | 43 +++++++
tools/filters/wiggle_to_simple.xml | 88 ++++++++++++++
9 files changed, 252 insertions(+), 0 deletions(-)
diffs (306 lines):
diff -r 6e742ffb16a5 -r eb317734e391 datatypes_conf.xml.sample
--- a/datatypes_conf.xml.sample Tue Dec 01 11:07:20 2009 -0500
+++ b/datatypes_conf.xml.sample Tue Dec 01 11:49:07 2009 -0500
@@ -58,6 +58,7 @@
<datatype extension="txtseq.zip" type="galaxy.datatypes.data:Txtseq" mimetype="application/zip" display_in_upload="true"/>
<datatype extension="wig" type="galaxy.datatypes.interval:Wiggle" display_in_upload="true">
<converter file="wiggle_to_array_tree_converter.xml" target_datatype="array_tree"/>
+ <converter file="wiggle_to_simple_converter.xml" target_datatype="interval"/>
</datatype>
<datatype extension="array_tree" type="galaxy.datatypes.data:Data" />
<datatype extension="interval_index" type="galaxy.datatypes.data:Data" />
diff -r 6e742ffb16a5 -r eb317734e391 lib/galaxy/datatypes/converters/wiggle_to_simple_converter.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/datatypes/converters/wiggle_to_simple_converter.py Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#code is same as ~/tools/stats/wiggle_to_simple.py
+
+"""
+Read a wiggle track and print out a series of lines containing
+"chrom position score". Ignores track lines, handles bed, variableStep
+and fixedStep wiggle lines.
+"""
+import sys
+from galaxy import eggs
+import pkg_resources; pkg_resources.require( "bx-python" )
+import bx.wiggle
+from galaxy.tools.exception_handling import *
+
+def stop_err( msg ):
+ sys.stderr.write( msg )
+ sys.exit()
+
+def main():
+ if len( sys.argv ) > 1:
+ in_file = open( sys.argv[1] )
+ else:
+ in_file = open( sys.stdin )
+
+ if len( sys.argv ) > 2:
+ out_file = open( sys.argv[2], "w" )
+ else:
+ out_file = sys.stdout
+
+ try:
+ for fields in bx.wiggle.IntervalReader( UCSCOutWrapper( in_file ) ):
+ out_file.write( "%s\n" % "\t".join( map( str, fields ) ) )
+ except UCSCLimitException:
+ # Wiggle data was truncated, at the very least need to warn the user.
+ print 'Encountered message from UCSC: "Reached output limit of 100000 data values", so be aware your data was truncated.'
+ except ValueError, e:
+ in_file.close()
+ out_file.close()
+ stop_err( str( e ) )
+
+ in_file.close()
+ out_file.close()
+
+if __name__ == "__main__": main()
diff -r 6e742ffb16a5 -r eb317734e391 lib/galaxy/datatypes/converters/wiggle_to_simple_converter.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/datatypes/converters/wiggle_to_simple_converter.xml Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,11 @@
+<tool id="CONVERTER_wiggle_to_interval_0" name="Wiggle to Interval">
+ <!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> -->
+ <!-- Used on the metadata edit page. -->
+ <command interpreter="python">wiggle_to_simple_converter.py $input $out_file1 </command>
+ <inputs>
+ <param format="wig" name="input" type="data" label="Convert"/>
+ </inputs>
+ <outputs>
+ <data format="interval" name="out_file1" />
+ </outputs>
+</tool>
diff -r 6e742ffb16a5 -r eb317734e391 test-data/3.wig
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/3.wig Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,37 @@
+track type=wiggle_0 name="LaminB1 (Tig3)" description="NKI LaminB1 DamID Map (log2-ratio scores, Tig3 cells)"
+# output date: 2009-07-22 15:55:44 UTC
+# chrom specified: chr20
+# position specified: 1-62435964
+# data values >= 4
+# This data has been compressed with a minor loss in resolution.
+# (Worst case: 0.0448672) The original source data
+# (before querying and compression) is available at
+# http://hgdownload.cse.ucsc.edu/downloads.html
+variableStep chrom=chr20 span=60
+1953668 4.029
+9749454 4.033
+12219969 4.053
+12571904 4.548
+12663417 4.207
+15198014 4.041
+16613945 4.526
+16994767 4.08
+19456653 4.014
+37706076 4.293
+38010695 4.14
+38418792 4.133
+38595669 4.032
+40038834 4.144
+50693133 4.206
+51294426 4
+52890600 4.12
+57414708 4.026
+57623989 4.031
+58977191 5.678
+59059925 4.325
+variableStep chrom=chr12 span=60
+1953668 -4.029
+9749454 -4.033
+12219969 -4.053
+12571904 -4.548
+12663417 -4.207
diff -r 6e742ffb16a5 -r eb317734e391 test-data/3_wig.bed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/3_wig.bed Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,26 @@
+chr20 1953667 1953727 + 4.029
+chr20 9749453 9749513 + 4.033
+chr20 12219968 12220028 + 4.053
+chr20 12571903 12571963 + 4.548
+chr20 12663416 12663476 + 4.207
+chr20 15198013 15198073 + 4.041
+chr20 16613944 16614004 + 4.526
+chr20 16994766 16994826 + 4.08
+chr20 19456652 19456712 + 4.014
+chr20 37706075 37706135 + 4.293
+chr20 38010694 38010754 + 4.14
+chr20 38418791 38418851 + 4.133
+chr20 38595668 38595728 + 4.032
+chr20 40038833 40038893 + 4.144
+chr20 50693132 50693192 + 4.206
+chr20 51294425 51294485 + 4.0
+chr20 52890599 52890659 + 4.12
+chr20 57414707 57414767 + 4.026
+chr20 57623988 57624048 + 4.031
+chr20 58977190 58977250 + 5.678
+chr20 59059924 59059984 + 4.325
+chr12 1953667 1953727 + -4.029
+chr12 9749453 9749513 + -4.033
+chr12 12219968 12220028 + -4.053
+chr12 12571903 12571963 + -4.548
+chr12 12663416 12663476 + -4.207
diff -r 6e742ffb16a5 -r eb317734e391 tool_conf.xml.main
--- a/tool_conf.xml.main Tue Dec 01 11:07:20 2009 -0500
+++ b/tool_conf.xml.main Tue Dec 01 11:49:07 2009 -0500
@@ -47,6 +47,7 @@
<tool file="maf/maf_to_fasta.xml" />
<tool file="fasta_tools/tabular_to_fasta.xml" />
<tool file="fastx_toolkit/fastq_to_fasta.xml" />
+ <tool file="filters/wiggle_to_simple.xml" />
</section>
<section name="FASTA manipulation" id="fasta_manipulation">
<tool file="fasta_tools/fasta_compute_length.xml" />
diff -r 6e742ffb16a5 -r eb317734e391 tool_conf.xml.sample
--- a/tool_conf.xml.sample Tue Dec 01 11:07:20 2009 -0500
+++ b/tool_conf.xml.sample Tue Dec 01 11:49:07 2009 -0500
@@ -71,6 +71,7 @@
<tool file="maf/maf_to_fasta.xml" />
<tool file="fasta_tools/tabular_to_fasta.xml" />
<tool file="fastx_toolkit/fastq_to_fasta.xml" />
+ <tool file="filters/wiggle_to_simple.xml" />
</section>
<section name="Extract Features" id="features">
<tool file="filters/ucsc_gene_bed_to_exon_bed.xml" />
diff -r 6e742ffb16a5 -r eb317734e391 tools/filters/wiggle_to_simple.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/filters/wiggle_to_simple.py Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+"""
+Read a wiggle track and print out a series of lines containing
+"chrom position score". Ignores track lines, handles bed, variableStep
+and fixedStep wiggle lines.
+"""
+import sys
+from galaxy import eggs
+import pkg_resources; pkg_resources.require( "bx-python" )
+import bx.wiggle
+from galaxy.tools.exception_handling import *
+
+def stop_err( msg ):
+ sys.stderr.write( msg )
+ sys.exit()
+
+def main():
+ if len( sys.argv ) > 1:
+ in_file = open( sys.argv[1] )
+ else:
+ in_file = open( sys.stdin )
+
+ if len( sys.argv ) > 2:
+ out_file = open( sys.argv[2], "w" )
+ else:
+ out_file = sys.stdout
+
+ try:
+ for fields in bx.wiggle.IntervalReader( UCSCOutWrapper( in_file ) ):
+ out_file.write( "%s\n" % "\t".join( map( str, fields ) ) )
+ except UCSCLimitException:
+ # Wiggle data was truncated, at the very least need to warn the user.
+ print 'Encountered message from UCSC: "Reached output limit of 100000 data values", so be aware your data was truncated.'
+ except ValueError, e:
+ in_file.close()
+ out_file.close()
+ stop_err( str( e ) )
+
+ in_file.close()
+ out_file.close()
+
+if __name__ == "__main__": main()
diff -r 6e742ffb16a5 -r eb317734e391 tools/filters/wiggle_to_simple.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/filters/wiggle_to_simple.xml Tue Dec 01 11:49:07 2009 -0500
@@ -0,0 +1,88 @@
+<tool id="wiggle2simple1" name="Wiggle-to-Interval">
+ <description>converter</description>
+ <command interpreter="python">wiggle_to_simple.py $input $out_file1 </command>
+ <inputs>
+ <param format="wig" name="input" type="data" label="Convert"/>
+ </inputs>
+ <outputs>
+ <data format="interval" name="out_file1" />
+ </outputs>
+ <tests>
+ <test>
+ <param name="input" value="2.wig" />
+ <output name="out_file1" file="2.interval"/>
+ </test>
+ <test>
+ <param name="input" value="3.wig" />
+ <output name="out_file1" file="3_wig.bed"/>
+ </test>
+ </tests>
+ <help>
+**Syntax**
+
+This tool converts wiggle data into interval type.
+
+- **Wiggle format**: The .wig format is line-oriented. Wiggle data is preceded by a UCSC track definition line. Following the track definition line is the track data, which can be entered in three different formats described below.
+
+ - **BED format** with no declaration line and four columns of data::
+
+ chromA chromStartA chromEndA dataValueA
+ chromB chromStartB chromEndB dataValueB
+
+ - **variableStep** two column data; started by a declaration line and followed with chromosome positions and data values::
+
+ variableStep chrom=chrN [span=windowSize]
+ chromStartA dataValueA
+ chromStartB dataValueB
+
+ - **fixedStep** single column data; started by a declaration line and followed with data values::
+
+ fixedStep chrom=chrN start=position step=stepInterval [span=windowSize]
+ dataValue1
+ dataValue2
+
+-----
+
+**Example**
+
+- input wiggle format file::
+
+ #track type=wiggle_0 name="Bed Format" description="BED format"
+ chr19 59302000 59302300 -1.0
+ chr19 59302300 59302600 -0.75
+ chr19 59302600 59302900 -0.50
+ chr19 59302900 59303200 -0.25
+ chr19 59303200 59303500 0.0
+ #track type=wiggle_0 name="variableStep" description="variableStep format"
+ variableStep chrom=chr19 span=150
+ 59304701 10.0
+ 59304901 12.5
+ 59305401 15.0
+ 59305601 17.5
+ #track type=wiggle_0 name="fixedStep" description="fixed step" visibility=full
+ fixedStep chrom=chr19 start=59307401 step=300 span=200
+ 1000
+ 900
+ 800
+ 700
+ 600
+
+- convert the above file to interval file::
+
+ chr19 59302000 59302300 + -1.0
+ chr19 59302300 59302600 + -0.75
+ chr19 59302600 59302900 + -0.5
+ chr19 59302900 59303200 + -0.25
+ chr19 59303200 59303500 + 0.0
+ chr19 59304701 59304851 + 10.0
+ chr19 59304901 59305051 + 12.5
+ chr19 59305401 59305551 + 15.0
+ chr19 59305601 59305751 + 17.5
+ chr19 59307701 59307901 + 1000.0
+ chr19 59308001 59308201 + 900.0
+ chr19 59308301 59308501 + 800.0
+ chr19 59308601 59308801 + 700.0
+ chr19 59308901 59309101 + 600.0
+
+</help>
+</tool>
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/f98643c26eb7
changeset: 3130:f98643c26eb7
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon Nov 30 17:53:25 2009 -0500
description:
Framework for recording user actions for reports; framework is modelled after event recording. Currently two types of actions are recorded: (a) tagging/untagging and (b) filtering/searching in grids.
diffstat:
lib/galaxy/config.py | 1 +
lib/galaxy/model/__init__.py | 10 +++++
lib/galaxy/model/mapping.py | 13 ++++++
lib/galaxy/model/migrate/versions/0029_user_actions.py | 47 +++++++++++++++++++++++
lib/galaxy/web/controllers/dataset.py | 2 +-
lib/galaxy/web/controllers/history.py | 2 +-
lib/galaxy/web/controllers/tag.py | 24 ++++++++---
lib/galaxy/web/framework/__init__.py | 17 ++++++++
lib/galaxy/web/framework/helpers/grids.py | 13 +++++-
templates/dataset/edit_attributes.mako | 2 +-
templates/history/view.mako | 2 +-
templates/root/history.mako | 2 +-
templates/tagging_common.mako | 8 ++--
universe_wsgi.ini.sample | 3 +
14 files changed, 128 insertions(+), 18 deletions(-)
diffs (335 lines):
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/config.py
--- a/lib/galaxy/config.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/config.py Mon Nov 30 17:53:25 2009 -0500
@@ -79,6 +79,7 @@
self.use_heartbeat = string_as_bool( kwargs.get( 'use_heartbeat', 'False' ) )
self.use_memdump = string_as_bool( kwargs.get( 'use_memdump', 'False' ) )
self.log_memory_usage = string_as_bool( kwargs.get( 'log_memory_usage', 'False' ) )
+ self.log_actions = string_as_bool( kwargs.get( 'log_actions', 'False' ) )
self.log_events = string_as_bool( kwargs.get( 'log_events', 'False' ) )
self.ucsc_display_sites = kwargs.get( 'ucsc_display_sites', "main,test,archaea,ucla" ).lower().split(",")
self.gbrowse_display_sites = kwargs.get( 'gbrowse_display_sites', "main,test,tair" ).lower().split(",")
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/model/__init__.py Mon Nov 30 17:53:25 2009 -0500
@@ -1441,6 +1441,16 @@
def __init__( self, name=None, value=None ):
self.name = name
self.value = value
+
+class UserAction( object ):
+ def __init__( self, id=None, create_time=None, user_id=None, session_id=None, action=None, params=None, context=None):
+ self.id = id
+ self.create_time = create_time
+ self.user_id = user_id
+ self.session_id = session_id
+ self.action = action
+ self.params = params
+ self.context = context
## ---- Utility methods -------------------------------------------------------
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/model/mapping.py Mon Nov 30 17:53:25 2009 -0500
@@ -743,6 +743,15 @@
Column( "name", Unicode( 255 ), index=True),
Column( "value", Unicode( 1024 ) ) )
+UserAction.table = Table( "user_action", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "action", Unicode( 255 ) ),
+ Column( "context", Unicode( 512 ) ),
+ Column( "params", Unicode( 1024 ) ) )
+
# With the tables defined we can define the mappers and setup the
# relationships between the model objects.
@@ -1237,6 +1246,10 @@
assign_mapper( context, UserPreference, UserPreference.table,
properties = {}
)
+
+assign_mapper( context, UserAction, UserAction.table,
+ properties = dict( user=relation( User.mapper ) )
+ )
def db_next_hid( self ):
"""
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/model/migrate/versions/0029_user_actions.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0029_user_actions.py Mon Nov 30 17:53:25 2009 -0500
@@ -0,0 +1,47 @@
+"""
+This migration script adds a user actions table to Galaxy.
+"""
+
+from sqlalchemy import *
+from migrate import *
+
+import datetime
+now = datetime.datetime.utcnow
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+
+def display_migration_details():
+ print ""
+ print "This migration script adds a user actions table to Galaxy."
+ print ""
+
+
+# New table to store user actions.
+UserAction_table = Table( "user_action", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "action", Unicode( 255 ) ),
+ Column( "context", Unicode( 512 ) ),
+ Column( "params", Unicode( 1024 ) ) )
+
+def upgrade():
+ display_migration_details()
+ metadata.reflect()
+ try:
+ UserAction_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating user_action table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+ try:
+ UserAction_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping user_action table failed: %s" % str( e ) )
\ No newline at end of file
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/web/controllers/dataset.py Mon Nov 30 17:53:25 2009 -0500
@@ -87,7 +87,7 @@
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced" ),
HistoryColumn( "History", key="history",
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ),
- grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced" ),
+ grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ),
StatusColumn( "Status", key="deleted", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/web/controllers/history.py Mon Nov 30 17:53:25 2009 -0500
@@ -94,7 +94,7 @@
link=( lambda history: iff( history.deleted, None, dict( operation="Switch", id=history.id ) ) ),
attach_popup=True, filterable="advanced" ),
DatasetsByStateColumn( "Datasets (by state)", ncells=4 ),
- grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"),
+ grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced", grid_name="HistoryListGrid" ),
StatusColumn( "Status", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/web/controllers/tag.py
--- a/lib/galaxy/web/controllers/tag.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/web/controllers/tag.py Mon Nov 30 17:53:25 2009 -0500
@@ -28,28 +28,38 @@
@web.expose
@web.require_login( "Add tag to an item." )
- def add_tag_async( self, trans, id=None, item_class=None, new_tag=None ):
+ def add_tag_async( self, trans, id=None, item_class=None, new_tag=None, context=None ):
""" Add tag to an item. """
- item = self._get_item(trans, item_class, trans.security.decode_id(id))
- self._do_security_check(trans, item)
+ # Check that user owns item.
+ item = self._get_item(trans, item_class, trans.security.decode_id( id ) )
+ self._do_security_check( trans, item )
+ # Apply tag.
self.tag_handler.apply_item_tags( trans.sa_session, item, new_tag.encode('utf-8') )
trans.sa_session.flush()
+ # Log.
+ params = dict( item_id=item.id, item_class=item_class, tag=new_tag)
+ trans.log_action( unicode( "tag"), context, params )
+
@web.expose
@web.require_login( "Remove tag from an item." )
- def remove_tag_async( self, trans, id=None, item_class=None, tag_name=None ):
+ def remove_tag_async( self, trans, id=None, item_class=None, tag_name=None, context=None ):
""" Remove tag from an item. """
+
+ # Check that user owns item.
item = self._get_item(trans, item_class, trans.security.decode_id(id))
-
self._do_security_check(trans, item)
+ # Remove tag.
self.tag_handler.remove_item_tag( trans, item, tag_name.encode('utf-8') )
- #print tag_name
- #print unicode(tag_name)
trans.sa_session.flush()
+ # Log.
+ params = dict( item_id=item.id, item_class=item_class, tag=tag_name)
+ trans.log_action( unicode( "untag"), context, params )
+
# Retag an item. All previous tags are deleted and new tags are applied.
@web.expose
@web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/web/framework/__init__.py Mon Nov 30 17:53:25 2009 -0500
@@ -10,6 +10,7 @@
import base
import pickle
from galaxy import util
+from galaxy.util.json import to_json_string
pkg_resources.require( "simplejson" )
import simplejson
@@ -170,6 +171,22 @@
to allow migration toward a more SQLAlchemy 0.4 style of use.
"""
return self.app.model.context.current
+ def log_action( self, action, context, params):
+ """
+ Application-level logging of user actions.
+ """
+ if self.app.config.log_actions:
+ action = self.app.model.UserAction(action=action, context=context, params=unicode( to_json_string( params ) ) )
+ try:
+ action.user = self.user
+ except:
+ action.user = None
+ try:
+ action.session_id = self.galaxy_session.id
+ except:
+ action.session_id = None
+ self.sa_session.add( action )
+ self.sa_session.flush()
def log_event( self, message, tool_id=None, **kwargs ):
"""
Application level logging. Still needs fleshing out (log levels and such)
diff -r 9d4945bbdcf5 -r f98643c26eb7 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Mon Nov 30 15:33:45 2009 -0500
+++ b/lib/galaxy/web/framework/helpers/grids.py Mon Nov 30 17:53:25 2009 -0500
@@ -200,6 +200,13 @@
trans.get_user().preferences[pref_name] = unicode( to_json_string( sort_key ) )
trans.sa_session.flush()
+ # Log grid view.
+ context = unicode( self.__class__.__name__ )
+ params = cur_filter_dict.copy()
+ params['sort'] = sort_key
+ params['async'] = ( 'async' in kwargs )
+ trans.log_action( unicode( "grid.view"), context, params )
+
# Render grid.
def url( *args, **kwargs ):
# Only include sort/filter arguments if not linking to another
@@ -340,17 +347,19 @@
# Generic column that supports tagging.
class TagsColumn( TextColumn ):
- def __init__( self, col_name, key, model_class, model_tag_association_class, filterable ):
+ def __init__( self, col_name, key, model_class, model_tag_association_class, filterable, grid_name=None ):
GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable)
self.model_tag_association_class = model_tag_association_class
# Tags cannot be sorted.
self.sortable = False
+ # Column-specific attributes.
self.tag_elt_id_gen = 0
+ self.grid_name = grid_name
def get_value( self, trans, grid, item ):
self.tag_elt_id_gen += 1
elt_id="tagging-elt" + str( self.tag_elt_id_gen )
div_elt = "<div id=%s></div>" % elt_id
- return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item,
+ return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item, elt_context=self.grid_name,
elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" )
def filter( self, db_session, query, column_filter ):
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
diff -r 9d4945bbdcf5 -r f98643c26eb7 templates/dataset/edit_attributes.mako
--- a/templates/dataset/edit_attributes.mako Mon Nov 30 15:33:45 2009 -0500
+++ b/templates/dataset/edit_attributes.mako Mon Nov 30 17:53:25 2009 -0500
@@ -59,7 +59,7 @@
</div>
<div style="clear: both"></div>
</div>
- ${render_tagging_element(data, "dataset-tag-area", use_toggle_link="false", in_form="true", input_size="30")}
+ ${render_tagging_element(data, "dataset-tag-area", "edit_attributes.mako", use_toggle_link="false", in_form="true", input_size="30")}
%endif
%for name, spec in data.metadata.spec.items():
%if spec.visible:
diff -r 9d4945bbdcf5 -r f98643c26eb7 templates/history/view.mako
--- a/templates/history/view.mako Mon Nov 30 15:33:45 2009 -0500
+++ b/templates/history/view.mako Mon Nov 30 17:53:25 2009 -0500
@@ -327,7 +327,7 @@
%if trans.get_user() is not None:
<div id='history-tag-area' class="tag-element"></div>
- ${render_tagging_element(history, "history-tag-area", use_toggle_link='false', get_toggle_link_text_fn='get_toggle_link_text', editable=user_owns_history)}
+ ${render_tagging_element(history, "history-tag-area", "history/view.mako", use_toggle_link='false', get_toggle_link_text_fn='get_toggle_link_text', editable=user_owns_history)}
%endif
%if not datasets:
diff -r 9d4945bbdcf5 -r f98643c26eb7 templates/root/history.mako
--- a/templates/root/history.mako Mon Nov 30 15:33:45 2009 -0500
+++ b/templates/root/history.mako Mon Nov 30 17:53:25 2009 -0500
@@ -325,7 +325,7 @@
%if trans.get_user() is not None:
<div id='history-tag-area' class="tag-element"></div>
- ${render_tagging_element(history, "history-tag-area", get_toggle_link_text_fn='get_toggle_link_text')}
+ ${render_tagging_element( tagged_item=history, elt_id="history-tag-area", elt_context="history.mako", get_toggle_link_text_fn='get_toggle_link_text' )}
%endif
%if not datasets:
diff -r 9d4945bbdcf5 -r f98643c26eb7 templates/tagging_common.mako
--- a/templates/tagging_common.mako Mon Nov 30 15:33:45 2009 -0500
+++ b/templates/tagging_common.mako Mon Nov 30 17:53:25 2009 -0500
@@ -1,10 +1,10 @@
## Render a tagging element if there is a tagged_item.
%if tagged_item is not None and elt_id is not None:
- ${render_tagging_element(tagged_item, elt_id=elt_id, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)}
+ ${render_tagging_element(tagged_item=tagged_item, elt_id=elt_id, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)}
%endif
## Render the tags 'tags' as an autocomplete element.
-<%def name="render_tagging_element(tagged_item, elt_id, use_toggle_link='true', in_form='false', input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable='true')">
+<%def name="render_tagging_element(tagged_item, elt_id, elt_context, use_toggle_link='true', in_form='false', input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable='true')">
<script type="text/javascript">
//
// Set up autocomplete tagger.
@@ -75,8 +75,8 @@
tag_click_fn: ${tag_click_fn},
<% tagged_item_id = trans.security.encode_id(tagged_item.id) %>
ajax_autocomplete_tag_url: "${h.url_for( controller='tag', action='tag_autocomplete_data', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
- ajax_add_tag_url: "${h.url_for( controller='tag', action='add_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
- ajax_delete_tag_url: "${h.url_for( controller='tag', action='remove_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
+ ajax_add_tag_url: "${h.url_for( controller='tag', action='add_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}",
+ ajax_delete_tag_url: "${h.url_for( controller='tag', action='remove_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}",
delete_tag_img: "${h.url_for('/static/images/delete_tag_icon_gray.png')}",
delete_tag_img_rollover: "${h.url_for('/static/images/delete_tag_icon_white.png')}",
add_tag_img: "${h.url_for('/static/images/add_icon.png')}",
diff -r 9d4945bbdcf5 -r f98643c26eb7 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample Mon Nov 30 15:33:45 2009 -0500
+++ b/universe_wsgi.ini.sample Mon Nov 30 17:53:25 2009 -0500
@@ -144,6 +144,9 @@
# Log events
log_events = True
+# Log user actions
+log_actions = True
+
# Configuration for debugging middleware
debug = True
use_lint = False
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/fe853d8e062d
changeset: 3136:fe853d8e062d
user: Kelly Vincent <kpvincent(a)bx.psu.edu>
date: Tue Dec 01 16:18:25 2009 -0500
description:
Added some error checking to pileup_parser tool so that it exits with a meaningful message if the user tries to do some 6-column work on a 10-column file, or vice versa.
diffstat:
tools/samtools/pileup_interval.py | 16 ++++++++++++++--
1 files changed, 14 insertions(+), 2 deletions(-)
diffs (40 lines):
diff -r eb317734e391 -r fe853d8e062d tools/samtools/pileup_interval.py
--- a/tools/samtools/pileup_interval.py Tue Dec 01 11:49:07 2009 -0500
+++ b/tools/samtools/pileup_interval.py Tue Dec 01 16:18:25 2009 -0500
@@ -1,7 +1,7 @@
#! /usr/bin/python
"""
-Creates a pileup file from a bam file and a reference.
+Condenses pileup format into ranges of bases.
usage: %prog [options]
-i, --input=i: Input pileup file
@@ -18,6 +18,7 @@
from galaxy import eggs
import pkg_resources; pkg_resources.require( "bx-python" )
from bx.cookbook import doc_optparse
+import sys
def stop_err( msg ):
sys.stderr.write( msg )
@@ -56,7 +57,18 @@
bases = []
while inLine.strip() != '':
lineParts = inLine.split('\t')
- seq, loc, base, cov = lineParts[seqIndex], int(lineParts[locIndex]), lineParts[baseIndex], int(lineParts[covIndex])
+ try:
+ seq, loc, base, cov = lineParts[seqIndex], int(lineParts[locIndex]), lineParts[baseIndex], int(lineParts[covIndex])
+ except IndexError, ei:
+ if options.format == 'ten':
+ stop_err( 'It appears that you have selected 10 columns while your file has 6. Make sure that the number of columns you specify matches the number in your file.\n' + str( ei ) )
+ else:
+ stop_err( 'There appears to be something wrong with your column index values.\n' + str( ei ) )
+ except ValueError, ev:
+ if options.format == 'six':
+ stop_err( 'It appears that you have selected 6 columns while your file has 10. Make sure that the number of columns you specify matches the number in your file.\n' + str( ev ) )
+ else:
+ stop_err( 'There appears to be something wrong with your column index values.\n' + str( ev ) )
# strout += str(startLoc) + '\n'
# strout += str(bases) + '\n'
# strout += '%s\t%s\t%s\t%s\n' % (seq, loc, base, cov)
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/e75b55cc9e08
changeset: 3133:e75b55cc9e08
user: Enis Afgan <afgane(a)gmail.com>
date: Tue Dec 01 09:53:36 2009 -0500
description:
Merge
diffstat:
lib/galaxy/config.py | 1 +
lib/galaxy/model/__init__.py | 10 +++++
lib/galaxy/model/mapping.py | 13 ++++++
lib/galaxy/model/migrate/versions/0029_user_actions.py | 47 +++++++++++++++++++++++
lib/galaxy/web/controllers/dataset.py | 2 +-
lib/galaxy/web/controllers/history.py | 2 +-
lib/galaxy/web/controllers/tag.py | 24 ++++++++---
lib/galaxy/web/framework/__init__.py | 17 ++++++++
lib/galaxy/web/framework/helpers/grids.py | 13 +++++-
templates/dataset/edit_attributes.mako | 2 +-
templates/history/view.mako | 2 +-
templates/root/history.mako | 2 +-
templates/tagging_common.mako | 8 ++--
universe_wsgi.ini.sample | 3 +
14 files changed, 128 insertions(+), 18 deletions(-)
diffs (335 lines):
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/config.py
--- a/lib/galaxy/config.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/config.py Tue Dec 01 09:53:36 2009 -0500
@@ -79,6 +79,7 @@
self.use_heartbeat = string_as_bool( kwargs.get( 'use_heartbeat', 'False' ) )
self.use_memdump = string_as_bool( kwargs.get( 'use_memdump', 'False' ) )
self.log_memory_usage = string_as_bool( kwargs.get( 'log_memory_usage', 'False' ) )
+ self.log_actions = string_as_bool( kwargs.get( 'log_actions', 'False' ) )
self.log_events = string_as_bool( kwargs.get( 'log_events', 'False' ) )
self.ucsc_display_sites = kwargs.get( 'ucsc_display_sites', "main,test,archaea,ucla" ).lower().split(",")
self.gbrowse_display_sites = kwargs.get( 'gbrowse_display_sites', "main,test,tair" ).lower().split(",")
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/model/__init__.py Tue Dec 01 09:53:36 2009 -0500
@@ -1441,6 +1441,16 @@
def __init__( self, name=None, value=None ):
self.name = name
self.value = value
+
+class UserAction( object ):
+ def __init__( self, id=None, create_time=None, user_id=None, session_id=None, action=None, params=None, context=None):
+ self.id = id
+ self.create_time = create_time
+ self.user_id = user_id
+ self.session_id = session_id
+ self.action = action
+ self.params = params
+ self.context = context
## ---- Utility methods -------------------------------------------------------
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/model/mapping.py Tue Dec 01 09:53:36 2009 -0500
@@ -743,6 +743,15 @@
Column( "name", Unicode( 255 ), index=True),
Column( "value", Unicode( 1024 ) ) )
+UserAction.table = Table( "user_action", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "action", Unicode( 255 ) ),
+ Column( "context", Unicode( 512 ) ),
+ Column( "params", Unicode( 1024 ) ) )
+
# With the tables defined we can define the mappers and setup the
# relationships between the model objects.
@@ -1237,6 +1246,10 @@
assign_mapper( context, UserPreference, UserPreference.table,
properties = {}
)
+
+assign_mapper( context, UserAction, UserAction.table,
+ properties = dict( user=relation( User.mapper ) )
+ )
def db_next_hid( self ):
"""
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/model/migrate/versions/0029_user_actions.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0029_user_actions.py Tue Dec 01 09:53:36 2009 -0500
@@ -0,0 +1,47 @@
+"""
+This migration script adds a user actions table to Galaxy.
+"""
+
+from sqlalchemy import *
+from migrate import *
+
+import datetime
+now = datetime.datetime.utcnow
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+
+def display_migration_details():
+ print ""
+ print "This migration script adds a user actions table to Galaxy."
+ print ""
+
+
+# New table to store user actions.
+UserAction_table = Table( "user_action", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True ),
+ Column( "action", Unicode( 255 ) ),
+ Column( "context", Unicode( 512 ) ),
+ Column( "params", Unicode( 1024 ) ) )
+
+def upgrade():
+ display_migration_details()
+ metadata.reflect()
+ try:
+ UserAction_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating user_action table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+ try:
+ UserAction_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping user_action table failed: %s" % str( e ) )
\ No newline at end of file
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/web/controllers/dataset.py Tue Dec 01 09:53:36 2009 -0500
@@ -87,7 +87,7 @@
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch", id=item.id ) ) ), filterable="advanced" ),
HistoryColumn( "History", key="history",
link=( lambda item: iff( item.history.deleted, None, dict( operation="switch_history", id=item.id ) ) ) ),
- grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced" ),
+ grids.TagsColumn( "Tags", "tags", model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, filterable="advanced", grid_name="HistoryDatasetAssocationListGrid" ),
StatusColumn( "Status", key="deleted", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/web/controllers/history.py Tue Dec 01 09:53:36 2009 -0500
@@ -94,7 +94,7 @@
link=( lambda history: iff( history.deleted, None, dict( operation="Switch", id=history.id ) ) ),
attach_popup=True, filterable="advanced" ),
DatasetsByStateColumn( "Datasets (by state)", ncells=4 ),
- grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"),
+ grids.TagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced", grid_name="HistoryListGrid" ),
StatusColumn( "Status", attach_popup=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/web/controllers/tag.py
--- a/lib/galaxy/web/controllers/tag.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/web/controllers/tag.py Tue Dec 01 09:53:36 2009 -0500
@@ -28,28 +28,38 @@
@web.expose
@web.require_login( "Add tag to an item." )
- def add_tag_async( self, trans, id=None, item_class=None, new_tag=None ):
+ def add_tag_async( self, trans, id=None, item_class=None, new_tag=None, context=None ):
""" Add tag to an item. """
- item = self._get_item(trans, item_class, trans.security.decode_id(id))
- self._do_security_check(trans, item)
+ # Check that user owns item.
+ item = self._get_item(trans, item_class, trans.security.decode_id( id ) )
+ self._do_security_check( trans, item )
+ # Apply tag.
self.tag_handler.apply_item_tags( trans.sa_session, item, new_tag.encode('utf-8') )
trans.sa_session.flush()
+ # Log.
+ params = dict( item_id=item.id, item_class=item_class, tag=new_tag)
+ trans.log_action( unicode( "tag"), context, params )
+
@web.expose
@web.require_login( "Remove tag from an item." )
- def remove_tag_async( self, trans, id=None, item_class=None, tag_name=None ):
+ def remove_tag_async( self, trans, id=None, item_class=None, tag_name=None, context=None ):
""" Remove tag from an item. """
+
+ # Check that user owns item.
item = self._get_item(trans, item_class, trans.security.decode_id(id))
-
self._do_security_check(trans, item)
+ # Remove tag.
self.tag_handler.remove_item_tag( trans, item, tag_name.encode('utf-8') )
- #print tag_name
- #print unicode(tag_name)
trans.sa_session.flush()
+ # Log.
+ params = dict( item_id=item.id, item_class=item_class, tag=tag_name)
+ trans.log_action( unicode( "untag"), context, params )
+
# Retag an item. All previous tags are deleted and new tags are applied.
@web.expose
@web.require_login( "Apply a new set of tags to an item; previous tags are deleted." )
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/web/framework/__init__.py Tue Dec 01 09:53:36 2009 -0500
@@ -10,6 +10,7 @@
import base
import pickle
from galaxy import util
+from galaxy.util.json import to_json_string
pkg_resources.require( "simplejson" )
import simplejson
@@ -170,6 +171,22 @@
to allow migration toward a more SQLAlchemy 0.4 style of use.
"""
return self.app.model.context.current
+ def log_action( self, action, context, params):
+ """
+ Application-level logging of user actions.
+ """
+ if self.app.config.log_actions:
+ action = self.app.model.UserAction(action=action, context=context, params=unicode( to_json_string( params ) ) )
+ try:
+ action.user = self.user
+ except:
+ action.user = None
+ try:
+ action.session_id = self.galaxy_session.id
+ except:
+ action.session_id = None
+ self.sa_session.add( action )
+ self.sa_session.flush()
def log_event( self, message, tool_id=None, **kwargs ):
"""
Application level logging. Still needs fleshing out (log levels and such)
diff -r efed28fa6a5e -r e75b55cc9e08 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Mon Nov 30 16:47:18 2009 -0500
+++ b/lib/galaxy/web/framework/helpers/grids.py Tue Dec 01 09:53:36 2009 -0500
@@ -200,6 +200,13 @@
trans.get_user().preferences[pref_name] = unicode( to_json_string( sort_key ) )
trans.sa_session.flush()
+ # Log grid view.
+ context = unicode( self.__class__.__name__ )
+ params = cur_filter_dict.copy()
+ params['sort'] = sort_key
+ params['async'] = ( 'async' in kwargs )
+ trans.log_action( unicode( "grid.view"), context, params )
+
# Render grid.
def url( *args, **kwargs ):
# Only include sort/filter arguments if not linking to another
@@ -340,17 +347,19 @@
# Generic column that supports tagging.
class TagsColumn( TextColumn ):
- def __init__( self, col_name, key, model_class, model_tag_association_class, filterable ):
+ def __init__( self, col_name, key, model_class, model_tag_association_class, filterable, grid_name=None ):
GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable)
self.model_tag_association_class = model_tag_association_class
# Tags cannot be sorted.
self.sortable = False
+ # Column-specific attributes.
self.tag_elt_id_gen = 0
+ self.grid_name = grid_name
def get_value( self, trans, grid, item ):
self.tag_elt_id_gen += 1
elt_id="tagging-elt" + str( self.tag_elt_id_gen )
div_elt = "<div id=%s></div>" % elt_id
- return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item,
+ return div_elt + trans.fill_template( "/tagging_common.mako", trans=trans, tagged_item=item, elt_context=self.grid_name,
elt_id = elt_id, in_form="true", input_size="20", tag_click_fn="add_tag_to_grid_filter" )
def filter( self, db_session, query, column_filter ):
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
diff -r efed28fa6a5e -r e75b55cc9e08 templates/dataset/edit_attributes.mako
--- a/templates/dataset/edit_attributes.mako Mon Nov 30 16:47:18 2009 -0500
+++ b/templates/dataset/edit_attributes.mako Tue Dec 01 09:53:36 2009 -0500
@@ -59,7 +59,7 @@
</div>
<div style="clear: both"></div>
</div>
- ${render_tagging_element(data, "dataset-tag-area", use_toggle_link="false", in_form="true", input_size="30")}
+ ${render_tagging_element(data, "dataset-tag-area", "edit_attributes.mako", use_toggle_link="false", in_form="true", input_size="30")}
%endif
%for name, spec in data.metadata.spec.items():
%if spec.visible:
diff -r efed28fa6a5e -r e75b55cc9e08 templates/history/view.mako
--- a/templates/history/view.mako Mon Nov 30 16:47:18 2009 -0500
+++ b/templates/history/view.mako Tue Dec 01 09:53:36 2009 -0500
@@ -327,7 +327,7 @@
%if trans.get_user() is not None:
<div id='history-tag-area' class="tag-element"></div>
- ${render_tagging_element(history, "history-tag-area", use_toggle_link='false', get_toggle_link_text_fn='get_toggle_link_text', editable=user_owns_history)}
+ ${render_tagging_element(history, "history-tag-area", "history/view.mako", use_toggle_link='false', get_toggle_link_text_fn='get_toggle_link_text', editable=user_owns_history)}
%endif
%if not datasets:
diff -r efed28fa6a5e -r e75b55cc9e08 templates/root/history.mako
--- a/templates/root/history.mako Mon Nov 30 16:47:18 2009 -0500
+++ b/templates/root/history.mako Tue Dec 01 09:53:36 2009 -0500
@@ -325,7 +325,7 @@
%if trans.get_user() is not None:
<div id='history-tag-area' class="tag-element"></div>
- ${render_tagging_element(history, "history-tag-area", get_toggle_link_text_fn='get_toggle_link_text')}
+ ${render_tagging_element( tagged_item=history, elt_id="history-tag-area", elt_context="history.mako", get_toggle_link_text_fn='get_toggle_link_text' )}
%endif
%if not datasets:
diff -r efed28fa6a5e -r e75b55cc9e08 templates/tagging_common.mako
--- a/templates/tagging_common.mako Mon Nov 30 16:47:18 2009 -0500
+++ b/templates/tagging_common.mako Tue Dec 01 09:53:36 2009 -0500
@@ -1,10 +1,10 @@
## Render a tagging element if there is a tagged_item.
%if tagged_item is not None and elt_id is not None:
- ${render_tagging_element(tagged_item, elt_id=elt_id, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)}
+ ${render_tagging_element(tagged_item=tagged_item, elt_id=elt_id, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)}
%endif
## Render the tags 'tags' as an autocomplete element.
-<%def name="render_tagging_element(tagged_item, elt_id, use_toggle_link='true', in_form='false', input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable='true')">
+<%def name="render_tagging_element(tagged_item, elt_id, elt_context, use_toggle_link='true', in_form='false', input_size='15', tag_click_fn='default_tag_click_fn', get_toggle_link_text_fn='default_get_toggle_link_text_fn', editable='true')">
<script type="text/javascript">
//
// Set up autocomplete tagger.
@@ -75,8 +75,8 @@
tag_click_fn: ${tag_click_fn},
<% tagged_item_id = trans.security.encode_id(tagged_item.id) %>
ajax_autocomplete_tag_url: "${h.url_for( controller='tag', action='tag_autocomplete_data', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
- ajax_add_tag_url: "${h.url_for( controller='tag', action='add_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
- ajax_delete_tag_url: "${h.url_for( controller='tag', action='remove_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__ )}",
+ ajax_add_tag_url: "${h.url_for( controller='tag', action='add_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}",
+ ajax_delete_tag_url: "${h.url_for( controller='tag', action='remove_tag_async', id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}",
delete_tag_img: "${h.url_for('/static/images/delete_tag_icon_gray.png')}",
delete_tag_img_rollover: "${h.url_for('/static/images/delete_tag_icon_white.png')}",
add_tag_img: "${h.url_for('/static/images/add_icon.png')}",
diff -r efed28fa6a5e -r e75b55cc9e08 universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample Mon Nov 30 16:47:18 2009 -0500
+++ b/universe_wsgi.ini.sample Tue Dec 01 09:53:36 2009 -0500
@@ -144,6 +144,9 @@
# Log events
log_events = True
+# Log user actions
+log_actions = True
+
# Configuration for debugging middleware
debug = True
use_lint = False
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/9d4945bbdcf5
changeset: 3129:9d4945bbdcf5
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Mon Nov 30 15:33:45 2009 -0500
description:
Fix MAF to BED tool. This tool should be rewritten to not use a code file, but instead use one of the standard ways to create additional outputs, similar to how maf_to_interval functions.
diffstat:
tools/maf/maf_to_bed.py | 3 +--
tools/maf/maf_to_bed.xml | 4 ++--
tools/maf/maf_to_bed_code.py | 1 +
3 files changed, 4 insertions(+), 4 deletions(-)
diffs (36 lines):
diff -r 92d6a9796b24 -r 9d4945bbdcf5 tools/maf/maf_to_bed.py
--- a/tools/maf/maf_to_bed.py Mon Nov 30 14:55:30 2009 -0500
+++ b/tools/maf/maf_to_bed.py Mon Nov 30 15:33:45 2009 -0500
@@ -15,8 +15,7 @@
input_filename = sys.argv[1]
output_filename = sys.argv[2]
#where to store files that become additional output
- database_tmp_dir = './database/tmp' #os.path.join(os.path.split(os.path.split(os.path.realpath(output_filename))[0])[0],'tmp') #database/tmp
-
+ database_tmp_dir = sys.argv[5]
species = sys.argv[3].split(',')
partial = sys.argv[4]
diff -r 92d6a9796b24 -r 9d4945bbdcf5 tools/maf/maf_to_bed.xml
--- a/tools/maf/maf_to_bed.xml Mon Nov 30 14:55:30 2009 -0500
+++ b/tools/maf/maf_to_bed.xml Mon Nov 30 15:33:45 2009 -0500
@@ -1,6 +1,6 @@
-<tool id="MAF_To_BED1" name="Maf to BED">
+<tool id="MAF_To_BED1" name="Maf to BED" force_history_refresh="True">
<description>Converts a MAF formated file to the BED format</description>
- <command interpreter="python">maf_to_bed.py $input1 $out_file1 $species $complete_blocks</command>
+ <command interpreter="python">maf_to_bed.py $input1 $out_file1 $species $complete_blocks $__new_file_path__</command>
<inputs>
<param format="maf" name="input1" type="data" label="MAF file to convert"/>
<param name="species" type="select" label="Select species" display="checkboxes" multiple="true" help="a separate history item will be created for each checked species">
diff -r 92d6a9796b24 -r 9d4945bbdcf5 tools/maf/maf_to_bed_code.py
--- a/tools/maf/maf_to_bed_code.py Mon Nov 30 14:55:30 2009 -0500
+++ b/tools/maf/maf_to_bed_code.py Mon Nov 30 15:33:45 2009 -0500
@@ -46,6 +46,7 @@
newdata.state = newdata.states.ERROR
newdata.dbkey = dbkey
newdata.init_meta()
+ newdata.set_meta()
newdata.set_peek()
app.model.context.flush()
output_data_list.append(newdata)
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/92d6a9796b24
changeset: 3128:92d6a9796b24
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Mon Nov 30 14:55:30 2009 -0500
description:
When setting metadata externally, substitute a MetadataTempFile object for all populated metadata FileParameters. Fixes the problem with writting to metadata FileParameter files on cluster nodes with read-only database/files directory.
diffstat:
lib/galaxy/datatypes/metadata.py | 21 +++-
lib/galaxy/model/mapping.py | 1 +
lib/galaxy/model/migrate/versions/0028_external_metadata_file_override.py | 47 +++++++++
scripts/set_metadata.py | 23 ++++-
tools/regVariation/quality_filter.xml | 2 +-
5 files changed, 87 insertions(+), 7 deletions(-)
diffs (172 lines):
diff -r 9f7a2a3be0e7 -r 92d6a9796b24 lib/galaxy/datatypes/metadata.py
--- a/lib/galaxy/datatypes/metadata.py Mon Nov 30 11:59:54 2009 -0500
+++ b/lib/galaxy/datatypes/metadata.py Mon Nov 30 14:55:30 2009 -0500
@@ -429,7 +429,9 @@
if MetadataTempFile.is_JSONified_value( value ):
value = MetadataTempFile.from_JSON( value )
if isinstance( value, MetadataTempFile ):
- mf = self.new_file( dataset = parent, **value.kwds )
+ mf = parent.metadata.get( self.spec.name, None)
+ if mf is None:
+ mf = self.new_file( dataset = parent, **value.kwds )
shutil.move( value.file_name, mf.file_name )
value = mf.id
return value
@@ -521,7 +523,7 @@
if dataset_path.false_path and dataset_path.real_path == metadata_files.dataset.file_name:
return dataset_path.false_path
return ""
- return "%s,%s,%s,%s,%s" % ( metadata_files.filename_in, metadata_files.filename_kwds, metadata_files.filename_out, metadata_files.filename_results_code, __get_filename_override() )
+ return "%s,%s,%s,%s,%s,%s" % ( metadata_files.filename_in, metadata_files.filename_kwds, metadata_files.filename_out, metadata_files.filename_results_code, __get_filename_override(), metadata_files.filename_override_metadata )
if not isinstance( datasets, list ):
datasets = [ datasets ]
if exec_dir is None:
@@ -558,11 +560,22 @@
open( metadata_files.filename_out, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible)
#file to store a 'return code' indicating the results of the set_meta() call
#results code is like (True/False - if setting metadata was successful/failed , exception or string of reason of success/failure )
- metadata_files.filename_results_code = relpath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_out_%s_" % key ).name )
+ metadata_files.filename_results_code = relpath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_results_%s_" % key ).name )
simplejson.dump( ( False, 'External set_meta() not called' ), open( metadata_files.filename_results_code, 'wb+' ) ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible)
#file to store kwds passed to set_meta()
metadata_files.filename_kwds = relpath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_kwds_%s_" % key ).name )
simplejson.dump( kwds, open( metadata_files.filename_kwds, 'wb+' ), ensure_ascii=True )
+ #existing metadata file parameters need to be overridden with cluster-writable file locations
+ metadata_files.filename_override_metadata = relpath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_override_%s_" % key ).name )
+ open( metadata_files.filename_override_metadata, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible)
+ override_metadata = []
+ for meta_key, spec_value in dataset.metadata.spec.iteritems():
+ if isinstance( spec_value.param, FileParameter ) and dataset.metadata.get( meta_key, None ) is not None:
+ metadata_temp = MetadataTempFile()
+ shutil.copy( dataset.metadata.get( meta_key, None ).file_name, metadata_temp.file_name )
+ override_metadata.append( ( meta_key, metadata_temp.to_JSON() ) )
+ simplejson.dump( override_metadata, open( metadata_files.filename_override_metadata, 'wb+' ) )
+ #add to session and flush
sa_session.add( metadata_files )
sa_session.flush()
metadata_files_list.append( metadata_files )
@@ -585,7 +598,7 @@
#can occur if the job was stopped before completion, but a MetadataTempFile is used in the set_meta
MetadataTempFile.cleanup_from_JSON_dict_filename( metadata_files.filename_out )
dataset_key = self.get_dataset_metadata_key( metadata_files.dataset )
- for key, fname in [ ( 'filename_in', metadata_files.filename_in ), ( 'filename_out', metadata_files.filename_out ), ( 'filename_results_code', metadata_files.filename_results_code ), ( 'filename_kwds', metadata_files.filename_kwds ) ]:
+ for key, fname in [ ( 'filename_in', metadata_files.filename_in ), ( 'filename_out', metadata_files.filename_out ), ( 'filename_results_code', metadata_files.filename_results_code ), ( 'filename_kwds', metadata_files.filename_kwds ), ( 'filename_override_metadata', metadata_files.filename_override_metadata ) ]:
try:
os.remove( fname )
except Exception, e:
diff -r 9f7a2a3be0e7 -r 92d6a9796b24 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Mon Nov 30 11:59:54 2009 -0500
+++ b/lib/galaxy/model/mapping.py Mon Nov 30 14:55:30 2009 -0500
@@ -358,6 +358,7 @@
Column( "filename_out", String( 255 ) ),
Column( "filename_results_code", String( 255 ) ),
Column( "filename_kwds", String( 255 ) ),
+ Column( "filename_override_metadata", String( 255 ) ),
Column( "job_runner_external_pid", String( 255 ) ) )
Event.table = Table( "event", metadata,
diff -r 9f7a2a3be0e7 -r 92d6a9796b24 lib/galaxy/model/migrate/versions/0028_external_metadata_file_override.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0028_external_metadata_file_override.py Mon Nov 30 14:55:30 2009 -0500
@@ -0,0 +1,47 @@
+"""
+This script adds the filename_override_metadata column to the JobExternalOutputMetadata table,
+allowing existing metadata files to be written when using external metadata and a cluster
+set up with read-only access to database/files
+"""
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from sqlalchemy.exceptions import *
+from migrate import *
+from migrate.changeset import *
+import datetime
+now = datetime.datetime.utcnow
+import sys, logging
+# Need our custom types, but don't import anything else from model
+from galaxy.model.custom_types import *
+
+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 )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+def display_migration_details():
+ print "========================================"
+ print "This script adds the filename_override_metadata column to the JobExternalOutputMetadata table,"
+ print" allowing existing metadata files to be written when using external metadata and a cluster"
+ print "set up with read-only access to database/files"
+ print "========================================"
+def upgrade():
+ display_migration_details()
+ # Load existing tables
+ metadata.reflect()
+ try:
+ job_external_output_metadata = Table( "job_external_output_metadata", metadata, autoload=True )
+ col = Column( "filename_override_metadata", String( 255 ) )
+ col.create( job_external_output_metadata )
+ assert col is job_external_output_metadata.c.filename_override_metadata
+ except Exception, e:
+ log.debug( "Adding column 'filename_override_metadata' to job_external_output_metadata table failed: %s" % ( str( e ) ) )
+
+def downgrade():
+ pass
diff -r 9f7a2a3be0e7 -r 92d6a9796b24 scripts/set_metadata.py
--- a/scripts/set_metadata.py Mon Nov 30 11:59:54 2009 -0500
+++ b/scripts/set_metadata.py Mon Nov 30 14:55:30 2009 -0500
@@ -50,17 +50,36 @@
except:
continue
for filenames in sys.argv[1:]:
- filename_in, filename_kwds, filename_out, filename_results_code, dataset_filename_override = filenames.split( ',' )
+ fields = filenames.split( ',' )
+ filename_in = fields.pop( 0 )
+ filename_kwds = fields.pop( 0 )
+ filename_out = fields.pop( 0 )
+ filename_results_code = fields.pop( 0 )
+ dataset_filename_override = fields.pop( 0 )
+ #Need to be careful with the way that these parameters are populated from the filename splitting,
+ #because if a job is running when the server is updated, any existing external metadata command-lines
+ #will not have info about the newly added override_metadata file
+ if fields:
+ override_metadata = fields.pop( 0 )
+ else:
+ override_metadata = None
try:
dataset = cPickle.load( open( filename_in ) ) #load DatasetInstance
if dataset_filename_override:
dataset.dataset.external_filename = dataset_filename_override
if ext_override.get( dataset.dataset.id, None ):
dataset.extension = ext_override[ dataset.dataset.id ]
+ #Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles
+ if override_metadata:
+ override_metadata = simplejson.load( open( override_metadata ) )
+ for metadata_name, metadata_file_override in override_metadata:
+ if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ):
+ metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override )
+ setattr( dataset.metadata, metadata_name, metadata_file_override )
kwds = stringify_dictionary_keys( simplejson.load( open( filename_kwds ) ) )#load kwds; need to ensure our keywords are not unicode
dataset.datatype.set_meta( dataset, **kwds )
dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta
- simplejson.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) #setting metadata has suceeded
+ simplejson.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) #setting metadata has succeeded
except Exception, e:
simplejson.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) #setting metadata has failed somehow
clear_mappers()
diff -r 9f7a2a3be0e7 -r 92d6a9796b24 tools/regVariation/quality_filter.xml
--- a/tools/regVariation/quality_filter.xml Mon Nov 30 11:59:54 2009 -0500
+++ b/tools/regVariation/quality_filter.xml Mon Nov 30 14:55:30 2009 -0500
@@ -61,7 +61,7 @@
</conditional>
</inputs>
<outputs>
- <data format="maf" name="out_file1"/>
+ <data format="maf" name="out_file1" metadata_source="input"/>
</outputs>
<requirements>
<requirement type="python-module">numpy</requirement>
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/9f7a2a3be0e7
changeset: 3127:9f7a2a3be0e7
user: guru
date: Mon Nov 30 11:59:54 2009 -0500
description:
Fixed a bug in 'fetch closest features' tool.
diffstat:
tools/new_operations/flanking_features.py | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diffs (22 lines):
diff -r 71b779fde315 -r 9f7a2a3be0e7 tools/new_operations/flanking_features.py
--- a/tools/new_operations/flanking_features.py Mon Nov 30 11:56:58 2009 -0500
+++ b/tools/new_operations/flanking_features.py Mon Nov 30 11:59:54 2009 -0500
@@ -121,7 +121,7 @@
map(outfields.append, result_down[-1].other) #The last element of result_down will be the closest element to the given interval
yield outfields
- if either:
+ if either and (result_up or result_down):
if result_up and result_down:
if abs(start - int(result_up[res_ind].end)) <= abs(end - int(result_down[-1].start)):
map(outfields.append, result_up[res_ind].other)
@@ -131,8 +131,7 @@
map(outfields.append, result_up[res_ind].other)
elif result_down:
map(outfields.append, result_down[-1].other) #The last element of result_down will be the closest element to the given interval
- yield outfields
-
+ yield outfields
def main():
options, args = doc_optparse.parse( __doc__ )
1
0
02 Dec '09
details: http://www.bx.psu.edu/hg/galaxy/rev/a8234f4d7012
changeset: 3125:a8234f4d7012
user: rc
date: Mon Nov 30 09:35:21 2009 -0500
description:
Fix for request_events table migration script for MySQL & sqlite
diffstat:
lib/galaxy/model/migrate/versions/0027_request_events.py | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diffs (16 lines):
diff -r 341d7c1c5c9a -r a8234f4d7012 lib/galaxy/model/migrate/versions/0027_request_events.py
--- a/lib/galaxy/model/migrate/versions/0027_request_events.py Mon Nov 30 09:05:28 2009 -0500
+++ b/lib/galaxy/model/migrate/versions/0027_request_events.py Mon Nov 30 09:35:21 2009 -0500
@@ -73,9 +73,10 @@
"%s AS create_time," + \
"%s AS update_time," + \
"request.id AS request_id," + \
- "request.state AS state " + \
+ "request.state AS state," + \
+ "'%s' AS comment " + \
"FROM request;"
- cmd = cmd % ( nextval('request_event'), localtimestamp(), localtimestamp() )
+ cmd = cmd % ( nextval('request_event'), localtimestamp(), localtimestamp(), 'Imported from request table')
db_session.execute( cmd )
# Delete the state column
1
0
02 Dec '09
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(a)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 )
1
0