galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
galaxy-dist commit 99f33c73bf81: Removed binseq.zip test and replace it with a zip test.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1277989166 14400
# Node ID 99f33c73bf815468400426870da113991e459efc
# Parent e110168a83c91f14a2923149e195aa4e8855fde5
Removed binseq.zip test and replace it with a zip test.
--- a/test/functional/test_get_data.py
+++ b/test/functional/test_get_data.py
@@ -90,35 +90,36 @@ class UploadData( TwillTestCase ):
self.check_history_for_string( "File Format' to 'Scf' when uploading scf files" )
self.delete_history( id=self.security.encode_id( history.id ) )
def test_0025_upload_file( self ):
- """Test uploading 1.scf.zip, manually setting the file format"""
+ """Test uploading 4.bed.zip, manually setting the file format"""
self.check_history_for_string( 'Your history is empty' )
history = sa_session.query( galaxy.model.History ) \
.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==admin_user.id ) ) \
.order_by( desc( galaxy.model.History.table.c.create_time ) ) \
.first()
- self.upload_file( '1.scf.zip', ftype='binseq.zip' )
+ self.upload_file( '4.bed.zip', ftype='bed' )
hda = sa_session.query( galaxy.model.HistoryDatasetAssociation ) \
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ) \
.first()
assert hda is not None, "Problem retrieving hda from database"
- self.verify_dataset_correctness( '1.scf.zip', hid=str( hda.hid ) )
- self.check_history_for_string( "Archive of 1 binary sequence files</pre>" )
+ self.verify_dataset_correctness( '4.bed', hid=str( hda.hid ) )
+ self.check_history_for_string( "<th>1.Chrom</th><th>2.Start</th><th>3.End</th>" )
self.delete_history( id=self.security.encode_id( history.id ) )
def test_0030_upload_file( self ):
- """Test uploading 1.scf.zip, NOT setting the file format"""
+ """Test uploading 4.bed.zip, NOT setting the file format"""
self.check_history_for_string( 'Your history is empty' )
history = sa_session.query( galaxy.model.History ) \
.filter( and_( galaxy.model.History.table.c.deleted==False,
galaxy.model.History.table.c.user_id==admin_user.id ) ) \
.order_by( desc( galaxy.model.History.table.c.create_time ) ) \
.first()
- self.upload_file( '1.scf.zip' )
+ self.upload_file( '4.bed.zip' )
hda = sa_session.query( galaxy.model.HistoryDatasetAssociation ) \
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ) \
.first()
assert hda is not None, "Problem retrieving hda from database"
- self.check_history_for_string( "'File Format' for archive consisting of binary files - use 'Binseq.zip'" )
+ self.verify_dataset_correctness( '4.bed', hid=str( hda.hid ) )
+ self.check_history_for_string( "<th>1.Chrom</th><th>2.Start</th><th>3.End</th>" )
self.delete_history( id=self.security.encode_id( history.id ) )
def test_0035_upload_file( self ):
"""Test uploading 1.sam NOT setting the file format"""
Binary file test-data/1.scf.zip has changed
Binary file test-data/4.bed.zip has changed
1
0
galaxy-dist commit b9bb8c131cd1: Merge, since I apparently keep forgetting to push my commits.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1277989841 14400
# Node ID b9bb8c131cd1a3364d3960640c724d2a786636ef
# Parent 99f33c73bf815468400426870da113991e459efc
# Parent 10027d1e6dc31200319f9d90a4d8233170393f2b
Merge, since I apparently keep forgetting to push my commits.
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -4,9 +4,10 @@ from galaxy.model.orm import *
from galaxy.datatypes import sniff
from galaxy import model, util
from galaxy.util.streamball import StreamBall
-import logging, tempfile, zipfile, tarfile, os, sys, subprocess
+import logging, tempfile, zipfile, tarfile, os, sys, subprocess, smtplib, socket
from galaxy.web.form_builder import *
from datetime import datetime, timedelta
+from email.MIMEText import MIMEText
from galaxy.web.controllers.forms import get_all_forms
from sqlalchemy.sql.expression import func, and_
from sqlalchemy.sql import select
@@ -474,13 +475,21 @@ class RequestsAdmin( BaseController ):
trans.sa_session.flush()
# now that the request is complete send the email notification to the
# the user
- if request.notify:
- mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w')
- subject = "Galaxy Sample Tracking: '%s' sequencing request in complete." % request.name
- body = "The '%s' sequencing request (type: %s) is now complete. Datasets from all the samples are now available for analysis or download from the respective data libraries in Galaxy." % (request.name, request.type.name)
- email_content = "To: %s\nFrom: no-reply(a)nowhere.edu\nSubject: %s\n\n%s" % (request.user.email, subject, body)
- mail.write( email_content )
- x = mail.close()
+ if request.notify and trans.app.config.smtp_server is not None:
+ host = trans.request.host.split(':')[0]
+ if host == 'localhost':
+ host = socket.getfqdn()
+ msg = MIMEText( "The '%s' sequencing request (type: %s) is now complete. Datasets from all the samples are now available for analysis or download from the respective data libraries in Galaxy." % ( request.name, request.type.name ) )
+ to = msg[ 'To' ] = request.user.email
+ frm = msg[ 'From' ] = 'galaxy-no-reply@' + host
+ msg[ 'Subject' ] = "Galaxy Sample Tracking: '%s' sequencing request in complete." % request.name
+ try:
+ s = smtplib.SMTP()
+ s.connect( trans.app.config.smtp_server )
+ s.sendmail( frm, [ to ], msg.as_string() )
+ s.close()
+ except:
+ pass
@web.expose
@web.require_admin
1
0
galaxy-dist commit 428ce38ba8e9: Fixed issue #345 - Incorporated Brad's patch which handles skipping of order checking for join version >=7, which would otherwise end in an error. Also modified sort command to better handle cases with duplicate keys. A new test-case to test these scenarios has been added as well.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User guru
# Date 1277915778 14400
# Node ID 428ce38ba8e92af0d2099a381e38863e09b46cd1
# Parent ddddd07724227dadeb37ffa2528a87e361787d8f
Fixed issue #345 - Incorporated Brad's patch which handles skipping of order checking for join version >=7, which would otherwise end in an error. Also modified sort command to better handle cases with duplicate keys. A new test-case to test these scenarios has been added as well.
--- a/tools/filters/joinWrapper.py
+++ b/tools/filters/joinWrapper.py
@@ -3,7 +3,7 @@
"""
This tool provides the UNIX "join" functionality.
"""
-import sys, os, tempfile
+import sys, os, tempfile, subprocess
def stop_err(msg):
sys.stderr.write(msg)
@@ -22,8 +22,8 @@ def main():
try:
#Sort the two files based on specified fields
- os.system("sort -t $'\t' -k %d -o %s %s" %(field1, tmpfile1.name, infile1))
- os.system("sort -t $'\t' -k %d -o %s %s" %(field2, tmpfile2.name, infile2))
+ os.system("sort -t $'\t' -k %d,%d -o %s %s" %(field1, field1, tmpfile1.name, infile1))
+ os.system("sort -t $'\t' -k %d,%d -o %s %s" %(field2, field2, tmpfile2.name, infile2))
except Exception, exc:
stop_err( 'Initialization error -> %s' %str(exc) )
@@ -39,10 +39,28 @@ def main():
option = option + ",1." + str(j)
break
+ #check if join has --version option. BSD join doens't have this option, while GNU join does.
+ #The return value in the latter case will be 0, and non-zero in the latter case.
+ ret = subprocess.call('join --version 2>/dev/null', shell=True)
+ # check if we are a version later than 7 of join. If so, we want to skip
+ # checking the order since join will raise an error with duplicated items in
+ # the two files being joined.
+ if ret == 0:
+ cl = subprocess.Popen(["join", "--version"], stdout=subprocess.PIPE)
+ (stdout, _) = cl.communicate()
+ version_line = stdout.split("\n")[0]
+ (version, _) = version_line.split()[-1].split(".")
+ if int(version) >= 7:
+ flags = "--nocheck-order"
+ else:
+ flags = ""
+ else:
+ flags = ""
+
if mode == "V":
- cmdline = "join -t $'\t' -v 1 -o %s -1 %d -2 %d %s %s > %s" %(option, field1, field2, tmpfile1.name, tmpfile2.name, outfile)
+ cmdline = "join %s -t $'\t' -v 1 -o %s -1 %d -2 %d %s %s > %s" %(flags, option, field1, field2, tmpfile1.name, tmpfile2.name, outfile)
else:
- cmdline = "join -t $'\t' -o %s -1 %d -2 %d %s %s > %s" %(option, field1, field2, tmpfile1.name, tmpfile2.name, outfile)
+ cmdline = "join %s -t $'\t' -o %s -1 %d -2 %d %s %s > %s" %(flags, option, field1, field2, tmpfile1.name, tmpfile2.name, outfile)
try:
os.system(cmdline)
--- /dev/null
+++ b/test-data/fs-compare-2.dat
@@ -0,0 +1,40 @@
+chr10 55251623 55253124 CCDS7248.1_cds_0_0_chr10_55251624_r 0 -
+chr11 116124407 116124501 CCDS8374.1_cds_0_0_chr11_116124408_r 0 -
+chr11 116206508 116206563 CCDS8377.1_cds_0_0_chr11_116206509_f 0 +
+chr11 116211733 116212337 CCDS8378.1_cds_0_0_chr11_116211734_r 0 -
+chr11 1812377 1812407 CCDS7726.1_cds_0_0_chr11_1812378_f 0 +
+chr12 38440094 38440321 CCDS8736.1_cds_0_0_chr12_38440095_r 0 -
+chr13 112381694 112381953 CCDS9526.1_cds_0_0_chr13_112381695_f 0 +
+chr14 98710240 98712285 CCDS9949.1_cds_0_0_chr14_98710241_r 0 -
+chr15 41486872 41487060 CCDS10096.1_cds_0_0_chr15_41486873_r 0 -
+chr15 41673708 41673857 CCDS10097.1_cds_0_0_chr15_41673709_f 0 +
+chr15 41679161 41679250 CCDS10098.1_cds_0_0_chr15_41679162_r 0 -
+chr15 41826029 41826196 CCDS10101.1_cds_0_0_chr15_41826030_f 0 +
+chr16 142908 143003 CCDS10397.1_cds_0_0_chr16_142909_f 0 +
+chr16 179963 180135 CCDS10401.1_cds_0_0_chr16_179964_r 0 -
+chr16 244413 244681 CCDS10402.1_cds_0_0_chr16_244414_f 0 +
+chr16 259268 259383 CCDS10403.1_cds_0_0_chr16_259269_r 0 -
+chr18 23786114 23786321 CCDS11891.1_cds_0_0_chr18_23786115_r 0 -
+chr18 59406881 59407046 CCDS11985.1_cds_0_0_chr18_59406882_f 0 +
+chr18 59455932 59456337 CCDS11986.1_cds_0_0_chr18_59455933_r 0 -
+chr18 59600586 59600754 CCDS11988.1_cds_0_0_chr18_59600587_f 0 +
+chr19 59068595 59069564 CCDS12866.1_cds_0_0_chr19_59068596_f 0 +
+chr19 59236026 59236146 CCDS12872.1_cds_0_0_chr19_59236027_r 0 -
+chr19 59297998 59298008 CCDS12877.1_cds_0_0_chr19_59297999_f 0 +
+chr19 59302168 59302288 CCDS12878.1_cds_0_0_chr19_59302169_r 0 -
+chr20 33330413 33330423 CCDS13249.1_cds_0_0_chr20_33330414_r 0 -
+chr20 33513606 33513792 CCDS13255.1_cds_0_0_chr20_33513607_f 0 +
+chr20 33579500 33579527 CCDS13256.1_cds_0_0_chr20_33579501_r 0 -
+chr20 33593260 33593348 CCDS13257.1_cds_0_0_chr20_33593261_f 0 +
+chr21 32707032 32707192 CCDS13614.1_cds_0_0_chr21_32707033_f 0 +
+chr21 32869641 32870022 CCDS13615.1_cds_0_0_chr21_32869642_r 0 -
+chr21 33321040 33322012 CCDS13620.1_cds_0_0_chr21_33321041_f 0 +
+chr21 33744994 33745040 CCDS13625.1_cds_0_0_chr21_33744995_r 0 -
+chr22 30120223 30120265 CCDS13897.1_cds_0_0_chr22_30120224_f 0 +
+chr22 30160419 30160661 CCDS13898.1_cds_0_0_chr22_30160420_r 0 -
+chr22 30665273 30665360 CCDS13901.1_cds_0_0_chr22_30665274_f 0 +
+chr22 30939054 30939266 CCDS13903.1_cds_0_0_chr22_30939055_r 0 -
+chrX 122745047 122745924 CCDS14606.1_cds_0_0_chrX_122745048_f 0 +
+chrX 152648964 152649196 CCDS14733.1_cds_0_0_chrX_152648965_r 0 -
+chrX 152691446 152691471 CCDS14735.1_cds_0_0_chrX_152691447_f 0 +
+chrX 152694029 152694263 CCDS14736.1_cds_0_0_chrX_152694030_r 0 -
--- a/tools/filters/compare.xml
+++ b/tools/filters/compare.xml
@@ -1,4 +1,4 @@
-<tool id="comp1" name="Compare two Queries" version="1.0.1">
+<tool id="comp1" name="Compare two Queries" version="1.0.2"><description>to find common or distinct rows</description><command interpreter="python">joinWrapper.py $input1 $input2 $field1 $field2 $mode $out_file1</command><inputs>
@@ -27,6 +27,15 @@
<param name="mode" value="N"/><output name="out_file1" file="fs-compare.dat"/></test>
+ <!--test case with duplicated key values-->
+ <test>
+ <param name="input1" value="1.bed"/>
+ <param name="input2" value="3.bed"/>
+ <param name="field1" value="1"/>
+ <param name="field2" value="1"/>
+ <param name="mode" value="V"/>
+ <output name="out_file1" file="fs-compare-2.dat"/>
+ </test></tests><help>
1
0
galaxy-dist commit e110168a83c9: lims: added option to rename sequencer datasets by prepending the experiment name.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1277922255 14400
# Node ID e110168a83c91f14a2923149e195aa4e8855fde5
# Parent 428ce38ba8e92af0d2099a381e38863e09b46cd1
lims: added option to rename sequencer datasets by prepending the experiment name.
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1554,6 +1554,7 @@ class RequestEvent( object ):
class RequestType( object ):
rename_dataset_options = Bunch( NO = 'Do not rename',
SAMPLE_NAME = 'Preprend sample name',
+ EXPERIMENT_NAME = 'Prepend experiment name',
EXPERIMENT_AND_SAMPLE_NAME = 'Prepend experiment and sample name')
permitted_actions = get_permitted_actions( filter='REQUEST_TYPE' )
def __init__(self, name=None, desc=None, request_form=None, sample_form=None,
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -673,6 +673,8 @@ class RequestsAdmin( BaseController ):
return sample.name+'_'+name
elif opt == sample.request.type.rename_dataset_options.EXPERIMENT_AND_SAMPLE_NAME:
return sample.request.name+'_'+sample.name+'_'+name
+ elif opt == sample.request.type.rename_dataset_options.EXPERIMENT_NAME:
+ return sample.request.name+'_'+name
def __setup_datatx_user(self, trans, library, folder):
'''
This method sets up the datatx user:
1
0
galaxy-dist commit ddddd0772422: Remove outdated about.rst/html.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dan Blankenberg <dan(a)bx.psu.edu>
# Date 1277910554 14400
# Node ID ddddd07724227dadeb37ffa2528a87e361787d8f
# Parent c1172bae7b0fc41e4bd52bfe73c130309c2387fe
Remove outdated about.rst/html.
--- a/static/about.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.3.9: http://docutils.sourceforge.net/" />
-<title>ABOUT GALAXY</title>
-<link rel="stylesheet" href="/static/style/base.css" type="text/css" />
-<link rel="stylesheet" href="/static/style/help.css" type="text/css" />
-</head>
-<body>
-<div class="document" id="about-galaxy">
-<h1 class="title">ABOUT GALAXY</h1>
-<div class="section" id="people">
-<h2><a name="people">People:</a></h2>
-<ul class="simple">
-<li>Istvan Albert - <em>Co-PI</em></li>
-<li>Daniel Blankenberg - <em>Graduate student</em></li>
-<li>Richard Burhans - <em>Sysadmin</em></li>
-<li>Laura Elnitski - <em>Co-PI</em></li>
-<li>Belinda Giardine - <em>Programmer</em></li>
-<li>Ross Hardison - <em>Co-PI</em></li>
-<li>Jim Kent - <em>Co-PI</em></li>
-<li>David King - <em>Graduate student</em></li>
-<li>Webb Miller - <em>Co-PI</em></li>
-<li>Anton Nekrutenko - <em>PI</em></li>
-<li>Cathy Riemer - <em>Programmer</em></li>
-<li>Prachi Shah - <em>Programmer</em></li>
-<li>Ian Schenck - <em>Undergraduate student</em></li>
-<li>James Taylor - <em>Graduate student</em></li>
-<li>Yi Zhang - <em>Programmer</em></li>
-</ul>
-</div>
-<hr class="docutils" />
-<div class="section" id="development">
-<h2><a name="development">Development:</a></h2>
-<p><strong>Galaxy core</strong> - <em>Istvan Albert</em> and <em>James Taylor</em></p>
-<p><strong>Interface</strong> - <em>James Taylor</em>, <em>Istvan Albert</em>, <em>Anton Nekrutenko</em></p>
-<p><strong>Tools</strong> -</p>
-<ul class="simple">
-<li>Data sources - <em>Istvan Albert</em></li>
-<li>EMBOSS, Phylip, mafs - <em>Daniel Blankenberg</em></li>
-<li>Text Tools, Sequence Extractors - <em>Richard Burhans</em>, <em>Anton Nekrutenko</em>, <em>Ian Schenck</em></li>
-<li>Operations - <em>James Taylor</em>, <em>Yi Zhang</em></li>
-<li>Statistics, Graphs - <em>Istvan Albert</em>, <em>David King</em></li>
-</ul>
-<p><strong>Project management</strong> - <em>Anton Nekrutenko</em></p>
-<p>Current version of Galaxy uses many ideas developed by <em>Laura Elnitski</em>, <em>Belinda Giardine</em>, and <em>Cathy Riemer</em> in Galaxy1 and GALA.</p>
-</div>
-<hr class="docutils" />
-<div class="section" id="special-thanks-to">
-<h2><a name="special-thanks-to">Special thanks to:</a></h2>
-<ul class="simple">
-<li>David Haussler</li>
-<li>Ewan Birney</li>
-<li>Hiram Clawson</li>
-<li>Angie Hinrichs</li>
-<li>Darin London</li>
-<li>Members of Hardison, Makova, Miller, and Nekrutenko Labs</li>
-</ul>
-</div>
-<hr class="docutils" />
-<div class="section" id="technology">
-<h2><a name="technology">Technology:</a></h2>
-<p>Galaxy core is written entirely in Python. It uses the following open source technologies:</p>
-<ul class="simple">
-<li>web-server <a class="reference" href="http://www.cherrypy.org/">CherryPy</a></li>
-<li>database <a class="reference" href="http://www.sleepycat.com/products/db.shtml">BerkelyDB</a></li>
-<li>XML library <a class="reference" href="http://effbot.org/zone/element-index.htm">ElementTree</a></li>
-<li>HTML templating library <a class="reference" href="http://www.cheetahtemplate.org/">Cheetah</a></li>
-</ul>
-<p>Galaxy API generated from source code can be found <a class="reference" href="http://www.bx.psu.edu/trac/local/docs/index.html">here</a></p>
-<hr class="docutils" />
-<p><a class="reference" href="http://www.bx.psu.edu">The Center for Comparative Genomics and Bioinformatics</a> at <a class="reference" href="http://www.psu.edu">Penn State</a> | 2005</p>
-</div>
-</div>
-</body>
-</html>
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,6 @@
static: static/welcome.html
static: static/help.html
static: static/galaxyIndex.html
-static: static/about.html
%.html : %.rst
./modules/rst2html.py --stylesheet="/static/help.css" --initial-header-level=2 < $< > $@
--- a/static/about.rst
+++ /dev/null
@@ -1,82 +0,0 @@
-ABOUT GALAXY
-============
-
-People:
--------
-
-* Istvan Albert - *Co-PI*
-* Daniel Blankenberg - *Graduate student*
-* Richard Burhans - *Sysadmin*
-* Laura Elnitski - *Co-PI*
-* Belinda Giardine - *Programmer*
-* Ross Hardison - *Co-PI*
-* Jim Kent - *Co-PI*
-* David King - *Graduate student*
-* Webb Miller - *Co-PI*
-* Anton Nekrutenko - *PI*
-* Cathy Riemer - *Programmer*
-* Prachi Shah - *Programmer*
-* Ian Schenck - *Undergraduate student*
-* James Taylor - *Graduate student*
-* Yi Zhang - *Programmer*
-
------
-
-Development:
-------------
-
-**Galaxy core** - *Istvan Albert* and *James Taylor*
-
-**Interface** - *James Taylor*, *Istvan Albert*, *Anton Nekrutenko*
-
-**Tools** -
-
-* Data sources - *Istvan Albert*
-* EMBOSS, Phylip, mafs - *Daniel Blankenberg*
-* Text Tools, Sequence Extractors - *Richard Burhans*, *Anton Nekrutenko*, *Ian Schenck*
-* Operations - *James Taylor*, *Yi Zhang*
-* Statistics, Graphs - *Istvan Albert*, *David King*
-
-**Project management** - *Anton Nekrutenko*
-
-Current version of Galaxy uses many ideas developed by *Laura Elnitski*, *Belinda Giardine*, and *Cathy Riemer* in Galaxy1 and GALA.
-
------
-
-Special thanks to:
-------------------
-
-* David Haussler
-* Ewan Birney
-* Hiram Clawson
-* Angie Hinrichs
-* Darin London
-* Members of Hardison, Makova, Miller, and Nekrutenko Labs
-
------
-
-Technology:
------------
-
-Galaxy core is written entirely in Python. It uses the following open source technologies:
-
-* web-server `CherryPy`__
-* database `BerkelyDB`__
-* XML library `ElementTree`__
-* HTML templating library `Cheetah`__
-
-Galaxy API generated from source code can be found `here`__
-
-.. __: http://www.cherrypy.org/
-.. __: http://www.sleepycat.com/products/db.shtml
-.. __: http://effbot.org/zone/element-index.htm
-.. __: http://www.cheetahtemplate.org/
-.. __: http://www.bx.psu.edu/trac/local/docs/index.html
-
------
-
-`The Center for Comparative Genomics and Bioinformatics`__ at `Penn State`__ | 2005
-
-.. __: http://www.bx.psu.edu
-.. __: http://www.psu.edu
-
1
0
galaxy-dist commit c1172bae7b0f: lims: requests/request_admin controller refactor
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User rc
# Date 1277909210 14400
# Node ID c1172bae7b0fc41e4bd52bfe73c130309c2387fe
# Parent 9289b4d7fa4d1d1b630c044dfbc102cf870f62e3
lims: requests/request_admin controller refactor
A new controller called requests_common now handles all common tasks like create/edit/delete requests & samples. The requests controller has only the grid definition and requests_admin controller has the request_type code and the sequencer data transfer code.
Also fixed a form importer bug in forms.py
--- /dev/null
+++ b/templates/requests/common/sample_events.mako
@@ -0,0 +1,65 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%def name="title()">Events for Sample ${sample.name}</%def>
+
+<h2>Events for Sample "${sample.name}"</h2>
+<ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, action='list', operation='show', id=trans.security.encode_id(sample.request.id) )}">
+ <span>Browse this request</span></a>
+ </li>
+</ul>
+<h3>User: ${sample.request.user.email}</h3>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<div class="toolForm">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>State</th>
+ <th>Description</th>
+ <th>Last Update</th>
+ <th>Comments</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for state, desc, updated, comments in events_list:
+ <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
+ <td><b><a>${state}</a></b></td>
+ <td><a>${desc}</a></td>
+ <td><a>${updated}</a></td>
+ <td><a>${comments}</a></td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+</div>
+%if cntrller == 'requests_admin' and trans.user_is_admin():
+ <div class="toolForm">
+ <div class="toolFormTitle">Change current state</div>
+ <div class="toolFormBody">
+ <form name="event" action="${h.url_for( controller='requests_admin', action='save_state', new=True, sample_id=sample.id)}" method="post" >
+ %for w in widgets:
+ <div class="form-row">
+ <label>
+ ${w[0]}
+ </label>
+ ${w[1].get_html()}
+ %if w[0] == 'Comments':
+ <div class="toolParamHelp" style="clear: both;">
+ Optional
+ </div>
+ %endif
+ </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="add_event_button" value="Save"/>
+ </div>
+ </form>
+ </div>
+ </div>
+%endif
--- a/test/functional/test_forms_and_requests.py
+++ b/test/functional/test_forms_and_requests.py
@@ -189,7 +189,7 @@ class TestFormsAndRequests( TwillTestCas
# Make sure the request_type is not accessible by regular_user2 since regular_user2 does not have Role1.
self.logout()
self.login( email=regular_user2.email )
- self.visit_url( '%s/requests/new?create=True&select_request_type=%i' % (self.url, request_type.id) )
+ self.visit_url( '%s/requests_common/new?cntrller=requests&select_request_type=True' % self.url )
try:
self.check_page_for_string( 'There are no request types created for a new request.' )
raise AssertionError, 'The request_type %s is accessible by %s when it should be restricted' % ( request_type.name, regular_user2.email )
@@ -304,12 +304,12 @@ class TestFormsAndRequests( TwillTestCas
self.logout()
self.login( email='test(a)bx.psu.edu' )
self.check_request_admin_grid(state=request_one.states.SUBMITTED, request_name=request_one.name)
- self.visit_url( "%s/requests_admin/list?sort=-create_time&operation=show_request&id=%s" \
+ self.visit_url( "%s/requests_admin/list?operation=show&id=%s" \
% ( self.url, self.security.encode_id( request_one.id ) ))
self.check_page_for_string( 'Sequencing Request "%s"' % request_one.name )
# set bar codes for the samples
bar_codes = [ '1234567890', '0987654321' ]
- self.add_bar_codes( request_one.id, request_one.name, bar_codes )
+ self.add_bar_codes( request_one.id, request_one.name, bar_codes, request_one.samples )
# change the states of all the samples of this request
for sample in request_one.samples:
self.change_sample_state( sample.name, sample.id, request_type.states[1].id, request_type.states[1].name )
@@ -328,11 +328,12 @@ class TestFormsAndRequests( TwillTestCas
self.login( email='test(a)bx.psu.edu' )
request_name = "RequestTwo"
# simulate request creation
- url_str = '%s/requests_admin/new?create=True&create_request_button=Save&select_request_type=%i&select_user=%i&name=%s&library_id=%i&folder_id=%i&refresh=True&field_2=%s&field_0=%s&field_1=%i' \
- % ( self.url, request_type.id, regular_user.id, request_name, library_one.id, library_one.root_folder.id, "field_2_value", 'option1', user_address.id )
+ url_str = '%s/requests_common/new?cntrller=requests_admin&create_request_button=Save&select_request_type=%i&select_user=%i&name=%s&refresh=True&field_2=%s&field_0=%s&field_1=%i' \
+ % ( self.url, request_type.id, regular_user.id, request_name, "field_2_value", 'option1', user_address.id )
+ print url_str
self.home()
self.visit_url( url_str )
- self.check_page_for_string( "The new request named %s has been created" % request_name )
+ self.check_page_for_string( "The new request named <b>%s</b> has been created" % request_name )
global request_two
request_two = sa_session.query( galaxy.model.Request ) \
.filter( and_( galaxy.model.Request.table.c.name==request_name,
@@ -370,44 +371,44 @@ class TestFormsAndRequests( TwillTestCas
# check if the request's state is now set to 'submitted'
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 )
- def test_055_reset_data_for_later_test_runs( self ):
- """Reseting data to enable later test runs to pass"""
- # Logged in as admin_user
- # remove the request_type permissions
- rt_actions = sa_session.query( galaxy.model.RequestTypePermissions ) \
- .filter(and_(galaxy.model.RequestTypePermissions.table.c.request_type_id==request_type.id) ) \
- .order_by( desc( galaxy.model.RequestTypePermissions.table.c.create_time ) ) \
- .all()
- for a in rt_actions:
- sa_session.delete( a )
- sa_session.flush()
- ##################
- # Purge all libraries
- ##################
- for library in [ library_one ]:
- self.delete_library_item( 'library_admin',
- self.security.encode_id( library.id ),
- self.security.encode_id( library.id ),
- library.name,
- item_type='library' )
- self.purge_library( self.security.encode_id( library.id ), library.name )
- ##################
- # Eliminate all non-private roles
- ##################
- for role in [ role_one, role_two ]:
- self.mark_role_deleted( self.security.encode_id( role.id ), role.name )
- self.purge_role( self.security.encode_id( role.id ), role.name )
- # Manually delete the role from the database
- sa_session.refresh( role )
- sa_session.delete( role )
- sa_session.flush()
- ##################
- # Eliminate all groups
- ##################
- for group in [ group_one ]:
- self.mark_group_deleted( self.security.encode_id( group.id ), group.name )
- self.purge_group( self.security.encode_id( group.id ), group.name )
- # Manually delete the group from the database
- refresh( group )
- sa_session.delete( group )
- sa_session.flush()
+# def test_055_reset_data_for_later_test_runs( self ):
+# """Reseting data to enable later test runs to pass"""
+# # Logged in as admin_user
+# # remove the request_type permissions
+# rt_actions = sa_session.query( galaxy.model.RequestTypePermissions ) \
+# .filter(and_(galaxy.model.RequestTypePermissions.table.c.request_type_id==request_type.id) ) \
+# .order_by( desc( galaxy.model.RequestTypePermissions.table.c.create_time ) ) \
+# .all()
+# for a in rt_actions:
+# sa_session.delete( a )
+# sa_session.flush()
+# ##################
+# # Purge all libraries
+# ##################
+# for library in [ library_one ]:
+# self.delete_library_item( 'library_admin',
+# self.security.encode_id( library.id ),
+# self.security.encode_id( library.id ),
+# library.name,
+# item_type='library' )
+# self.purge_library( self.security.encode_id( library.id ), library.name )
+# ##################
+# # Eliminate all non-private roles
+# ##################
+# for role in [ role_one, role_two ]:
+# self.mark_role_deleted( self.security.encode_id( role.id ), role.name )
+# self.purge_role( self.security.encode_id( role.id ), role.name )
+# # Manually delete the role from the database
+# sa_session.refresh( role )
+# sa_session.delete( role )
+# sa_session.flush()
+# ##################
+# # Eliminate all groups
+# ##################
+# for group in [ group_one ]:
+# self.mark_group_deleted( self.security.encode_id( group.id ), group.name )
+# self.purge_group( self.security.encode_id( group.id ), group.name )
+# # Manually delete the group from the database
+# refresh( group )
+# sa_session.delete( group )
+# sa_session.flush()
--- a/templates/admin/requests/show_request.mako
+++ /dev/null
@@ -1,528 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-<%namespace file="/requests/sample_state.mako" import="render_sample_state" />
-<%namespace file="/requests/sample_datasets.mako" import="render_sample_datasets" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#show_request" ).submit();
- }
- });
-});
-</script>
-
-
-<script type="text/javascript">
-$(document).ready(function(){
- //hide the all of the element with class msg_body
- $(".msg_body").hide();
- //toggle the componenet with class msg_body
- $(".msg_head").click(function(){
- $(this).next(".msg_body").slideToggle(450);
- });
-});
-</script>
-
-<script type="text/javascript">
- // Looks for changes in sample states using an async request. Keeps
- // calling itself (via setTimeout) until all samples are in a terminal
- // state.
- var updater = function ( sample_states ) {
- // Check if there are any items left to track
- var empty = true;
- for ( i in sample_states ) {
- empty = false;
- break;
- }
- if ( ! empty ) {
- setTimeout( function() { updater_callback( sample_states ) }, 1000 );
- }
- };
- var updater_callback = function ( sample_states ) {
- // Build request data
- var ids = []
- var states = []
- $.each( sample_states, function ( id, state ) {
- ids.push( id );
- states.push( state );
- });
- // Make ajax call
- $.ajax( {
- type: "POST",
- url: "${h.url_for( controller='requests_admin', action='sample_state_updates' )}",
- dataType: "json",
- data: { ids: ids.join( "," ), states: states.join( "," ) },
- success : function ( data ) {
- $.each( data, function( id, val ) {
- // Replace HTML
- var cell1 = $("#sampleState-" + id);
- cell1.html( val.html_state );
- var cell2 = $("#sampleDatasets-" + id);
- cell2.html( val.html_datasets );
- sample_states[ parseInt(id) ] = val.state;
- });
- updater( sample_states );
- },
- error: function() {
- // Just retry, like the old method, should try to be smarter
- updater( sample_states );
- }
- });
- };
-</script>
-
-<style type="text/css">
-.msg_head {
- padding: 0px 0px;
- cursor: pointer;
-}
-</style>
-
-<script type="text/javascript">
- function stopRKey(evt) {
- var evt = (evt) ? evt : ((event) ? event : null);
- var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
- if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
- }
- document.onkeypress = stopRKey
-</script>
-
-%if request.submitted():
- <% samples_not_ready = request.sequence_run_ready() %>
- %if samples_not_ready:
- ${render_msg( "Select a target library and folder for all the samples before starting the sequence run", "warning" )}
- %endif
-%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) )}">
- <span>Submit request</span></a>
- </li>
- %endif
- %if request.submitted():
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='Reject', id=trans.security.encode_id(request.id))}">
- <span>Reject request</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>
-
-<%def name="show_basic_info_form( sample_index, sample, info )">
- <td>
- <input type="text" name=sample_${sample_index}_name value="${info['name']}" size="10"/>
- <div class="toolParamHelp" style="clear: both;">
- <i>${' (required)' }</i>
- </div>
- </td>
- %if sample:
- %if sample.request.unsubmitted():
- <td></td>
- %else:
- <td><input type="text" name=sample_${sample_index}_barcode value="${info['barcode']}" size="10"/></td>
- %endif
- %else:
- <td></td>
- %endif
- %if sample:
- %if sample.request.unsubmitted():
- <td>Unsubmitted</td>
- %else:
- <td><a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a></td>
- %endif
- %else:
- <td></td>
- %endif
- <td>${info['lib_widget'].get_html()}</td>
- <td>${info['folder_widget'].get_html()}</td>
- %if request.submitted() or request.complete():
- %if sample:
- <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">${len(sample.dataset_files)}</a></td>
- %else:
- <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">Add</a></td>
- %endif
- %endif
-</%def>
-
-## This function displays the "Basic Information" grid
-<%def name="render_basic_info_grid()">
- <h4>Sample Information</h4>
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- <th>Barcode</th>
- <th>State</th>
- <th>Data Library</th>
- <th>Folder</th>
- %if request.submitted() or request.complete():
- <th>Dataset(s) Transferred</th>
- %endif
- <th></th>
- </tr>
- <thead>
- <tbody>
- <%
- trans.sa_session.refresh( request )
- %>
- %for sample_index, info in enumerate(current_samples):
- <%
- if sample_index in range(len(request.samples)):
- sample = request.samples[sample_index]
- else:
- sample = None
- %>
- %if edit_mode == 'True':
- <tr>
- ${show_basic_info_form( sample_index, sample, info )}
- </tr>
- %else:
- <tr>
- %if sample_index in range(len(request.samples)):
- <td>${info['name']}</td>
- <td>${info['barcode']}</td>
- %if sample.request.unsubmitted():
- <td>Unsubmitted</td>
- %else:
- <td id="sampleState-${sample.id}">${render_sample_state( sample )}</td>
- %endif
-
-## <td>
-## %if sample:
-## %if sample.request.unsubmitted():
-## Unsubmitted
-## %else:
-## <a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a>
-## %endif
-## %endif
-## </td>
- %if info['library']:
- <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( info['library'].id ) )}">${info['library'].name}</a></td>
- %else:
- <td></td>
- %endif
- %if info['folder']:
- <td>${info['folder'].name}</td>
- %else:
- <td></td>
- %endif
- %if request.submitted() or request.complete():
- <td id="sampleDatasets-${sample.id}">
- ${render_sample_datasets( sample )}
-## <a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">${len(sample.dataset_files)}</a>
- </td>
- %endif
-
-
- %else:
- ${show_basic_info_form( sample_index, sample, info )}
- %endif
- %if request.unsubmitted() or request.rejected():
- <td>
- %if sample:
- %if sample.request.unsubmitted():
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='delete_sample', request_id=request.id, sample_id=sample_index )}">
- <img src="${h.url_for('/static/images/delete_icon.png')}" />
- <span></span></a>
- %endif
- %endif
- </td>
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
-</%def>
-
-<%def name="render_sample_form( index, sample_name, sample_values, fields_dict )">
- <td>
- ${sample_name}
- </td>
- %for field_index, field in fields_dict.items():
- <td>
- %if field['type'] == 'TextField':
- <input type="text" name="sample_${index}_field_${field_index}" value="${sample_values[field_index]}" size="7"/>
- %elif field['type'] == 'SelectField':
- <select name="sample_${index}_field_${field_index}" last_selected_value="2">
- %for option_index, option in enumerate(field['selectlist']):
- %if option == sample_values[field_index]:
- <option value="${option}" selected>${option}</option>
- %else:
- <option value="${option}">${option}</option>
- %endif
- %endfor
- </select>
- %elif field['type'] == 'WorkflowField':
- <select name="sample_${index}_field_${field_index}">
- %if str(sample_values[field_index]) == 'none':
- <option value="none" selected>Select one</option>
- %else:
- <option value="none">Select one</option>
- %endif
- %for option_index, option in enumerate(request.user.stored_workflows):
- %if not option.deleted:
- %if str(option.id) == str(sample_values[field_index]):
- <option value="${option.id}" selected>${option.name}</option>
- %else:
- <option value="${option.id}">${option.name}</option>
- %endif
- %endif
- %endfor
- </select>
- %elif field['type'] == 'CheckboxField':
- <input type="checkbox" name="sample_${index}_field_${field_index}" value="Yes"/>
- %endif
- <div class="toolParamHelp" style="clear: both;">
- <i>${'('+field['required']+')' }</i>
- </div>
- </td>
- %endfor
-</%def>
-
-<%def name="render_sample( index, sample_name, sample_values, fields_dict )">
- <td>
- ${sample_name}
- </td>
- %for field_index, field in fields_dict.items():
- <td>
- %if sample_values[field_index]:
- %if field['type'] == 'WorkflowField':
- %if str(sample_values[field_index]) != 'none':
- <% workflow = trans.sa_session.query( trans.app.model.StoredWorkflow ).get( int(sample_values[field_index]) ) %>
- <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
- %endif
- %else:
- ${sample_values[field_index]}
- %endif
- %else:
- <i>None</i>
- %endif
- </td>
- %endfor
-</%def>
-
-<div class="toolForm">
- <div class="form-row">
- <div class="msg_list">
- <h4 class="msg_head"><u>Request Information</u></h4>
- <div class="msg_body">
- %for index, rd in enumerate(request_details):
- <div class="form-row">
- <label>${rd['label']}</label>
- %if not rd['value']:
- <i>None</i>
- %else:
- %if 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
- %endif
- </div>
- <div style="clear: both"></div>
- %endfor
- <div class="form-row">
- <ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='Edit', id=trans.security.encode_id(request.id))}">
- <span>Edit request details</span></a>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
-</div>
-
-<br/>
-
-
-<%def name="render_grid( grid_index, grid_name, fields_dict )">
- <br/>
- <div class="msg_list">
- %if grid_name:
- <h4 class="msg_head"><u>${grid_name}</u></h4>
- %else:
- <h4>Grid ${grid_index}</h4>
- %endif
- %if edit_mode == 'False' or len(current_samples) <= len(request.samples):
- <div class="msg_body">
- %else:
- <div class="msg_body2">
- %endif
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- %for index, field in fields_dict.items():
- <th>
- ${field['label']}
- <div class="toolParamHelp" style="clear: both;">
- <i>${field['helptext']}</i>
- </div>
- </th>
- %endfor
- <th></th>
- </tr>
- <thead>
- <tbody>
- <%
- trans.sa_session.refresh( request )
- %>
- %for sample_index, sample in enumerate(current_samples):
- %if edit_mode == 'True':
- <tr>
- ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
- </tr>
- %else:
- <tr>
- %if sample_index in range(len(request.samples)):
- ${render_sample( sample_index, sample['name'], sample['field_values'], fields_dict )}
- %else:
- ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
- </div>
- </div>
-</%def>
-
-<div class="toolForm">
- ##<div class="toolFormTitle">Samples (${len(request.samples)})</div>
- <form id="show_request" name="show_request" action="${h.url_for( controller='requests_admin', action='show_request', edit_mode=edit_mode )}" enctype="multipart/form-data" method="post" >
- <div class="form-row">
- %if current_samples:
- ## first render the basic info grid
- ${render_basic_info_grid()}
- ## then render the other grid(s)
- <% trans.sa_session.refresh( request.type.sample_form ) %>
- %for grid_index, grid_name in enumerate(request.type.sample_form.layout):
- ${render_grid( grid_index, grid_name, request.type.sample_form.fields_of_grid( grid_index ) )}
- <br/>
- %endfor
- %else:
- <label>There are no samples.</label>
- %endif
- </div>
- %if request.samples and request.submitted():
- <script type="text/javascript">
- // Updater
- updater({${ ",".join( [ '"%s" : "%s"' % ( s.id, s.current_state().name ) for s in request.samples ] ) }});
- </script>
- %endif
-
- %if edit_mode == 'False':
- <table class="grid">
- <tbody>
- <tr>
- <div class="form-row">
-
- %if request.unsubmitted():
- <td>
- %if current_samples:
- <label>Copy </label>
- <input type="integer" name="num_sample_to_copy" value="1" size="3"/>
- <label>sample(s) from sample</label>
- ${sample_copy.get_html()}
- %endif
- <input type="submit" name="add_sample_button" value="Add New"/>
- </td>
- %endif
- <td>
- %if len(current_samples) and len(current_samples) <= len(request.samples):
- <input type="submit" name="edit_samples_button" value="Edit samples"/>
- %endif
- </td>
- </div>
- </tr>
- </tbody>
- </table>
- %endif
- %if request.samples or current_samples:
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- %if edit_mode == 'True':
- <div class="form-row">
- <input type="submit" name="save_samples_button" value="Save"/>
- <input type="submit" name="cancel_changes_button" value="Cancel"/>
- </div>
- %elif request.unsubmitted():
- <div class="form-row">
- <input type="submit" name="save_samples_button" value="Save"/>
- </div>
- %endif
-
- %endif
- <input type="hidden" name="request_id" value="${request.id}" />
- </form>
-</div>
-
-<br/>
-
-%if request.unsubmitted():
-<div class="toolForm">
- <form id="show_request" name="show_request" action="${h.url_for( controller='requests_admin', action='show_request', edit_mode=edit_mode )}" enctype="multipart/form-data" method="post" >
- <div class="form-row">
- <div class="msg_list">
- <h4 class="msg_head"><u>Import samples from csv file</u></h4>
- <div class="msg_body">
- <input type="file" name="file_data" />
- <input type="submit" name="import_samples_button" value="Import samples"/>
- <br/>
- <div class="toolParamHelp" style="clear: both;">
- The csv file must be in the following format:<br/>
- SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...
- </div>
- </div>
- </div>
- </div>
- <input type="hidden" name="request_id" value="${request.id}" />
- </form>
-</div>
-%endif
-
--- a/templates/admin/samples/events.mako
+++ /dev/null
@@ -1,63 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<%def name="title()">Events for Sample ${sample.name}</%def>
-
-<h2>Events for Sample "${sample.name}"</h2>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='show_request', id=trans.security.encode_id(sample.request.id) )}">
- <span>Browse this request</span></a>
- </li>
-</ul>
-<h3>User: ${sample.request.user.email}</h3>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<div class="toolForm">
- <table class="grid">
- <thead>
- <tr>
- <th>State</th>
- <th>Description</th>
- <th>Last Update</th>
- <th>Comments</th>
- </tr>
- </thead>
- <tbody>
- %for state, desc, updated, comments in events_list:
- <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><b><a>${state}</a></b></td>
- <td><a>${desc}</a></td>
- <td><a>${updated}</a></td>
- <td><a>${comments}</a></td>
- </tr>
- %endfor
- </tbody>
- </table>
-</div>
-<div class="toolForm">
- <div class="toolFormTitle">Change current state</div>
- <div class="toolFormBody">
- <form name="event" action="${h.url_for( controller='requests_admin', action='save_state', new=True, sample_id=sample.id)}" method="post" >
- %for w in widgets:
- <div class="form-row">
- <label>
- ${w[0]}
- </label>
- ${w[1].get_html()}
- %if w[0] == 'Comments':
- <div class="toolParamHelp" style="clear: both;">
- Optional
- </div>
- %endif
- </div>
- %endfor
- <div class="form-row">
- <input type="submit" name="add_event_button" value="Save"/>
- </div>
- </form>
- </div>
-</div>
--- a/scripts/galaxy_messaging/server/data_transfer.py
+++ b/scripts/galaxy_messaging/server/data_transfer.py
@@ -194,7 +194,7 @@ class DataTransfer(object):
Update the data transfer status for this dataset in the database
'''
try:
- log.debug('Setting status "%s" for dataset "%s"' % ( status, str(dataset_index) ) )
+ log.debug('Setting status "%s" for dataset "%s" of sample "%s"' % ( status, str(dataset_index), str(self.sample_id) ) )
df = from_json_string(self.galaxydb.get_sample_dataset_files(self.sample_id))
if dataset_index == 'All':
for dataset in self.dataset_files:
--- a/scripts/galaxy_messaging/server/galaxydb_interface.py
+++ b/scripts/galaxy_messaging/server/galaxydb_interface.py
@@ -28,7 +28,7 @@ class GalaxyDbInterface(object):
def __init__(self, dbstr):
self.dbstr = dbstr
self.db_engine = create_engine(self.dbstr)
-# self.db_engine.echo = True
+ self.db_engine.echo = True
self.metadata = MetaData(self.db_engine)
self.session = sessionmaker(bind=self.db_engine)
self.event_table = Table('sample_event', self.metadata, autoload=True )
--- a/templates/requests/sample_state.mako
+++ /dev/null
@@ -1,5 +0,0 @@
-<%def name="render_sample_state( sample )">
- <a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a>
-</%def>
-
-${render_sample_state( sample )}
--- a/templates/admin/requests/dataset.mako
+++ b/templates/admin/requests/dataset.mako
@@ -11,7 +11,7 @@
<ul class="manage-table-actions"><li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='show_datatx_page', cntrller='requests_admin', sample_id=trans.security.encode_id(sample.id) )}"><span>Dataset transfer page</span></a></li></ul>
--- a/templates/admin/samples/bar_codes.mako
+++ /dev/null
@@ -1,46 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-
-<h2>Bar codes for Samples of Request "${request.name}"</h2>
-<h3>User: ${user.email}</h3>
-
-<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>
-
-<div class="toolForm">
- <form name="bar_codes" action="${h.url_for( controller='requests_admin', action='save_bar_codes', request_id=request.id)}" method="post" >
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- <th>Description</th>
- <th>Bar code</th>
- </tr>
- </thead>
- <tbody>
- %for index, sample in enumerate(samples_list):
- <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><b><a>${sample.name}</a></b></td>
- <td><a>${sample.desc}</a></td>
- <td>
- ${widgets[index].get_html()}
- </td>
- </tr>
- %endfor
- </tbody>
- </table>
- <div class="form-row">
- <input type="submit" name="save_bar_codes" value="Save"/>
- </div>
- </form>
-</div>
--- a/templates/requests/edit_request.mako
+++ /dev/null
@@ -1,84 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#edit_request" ).submit();
- }
- });
-});
-</script>
-
-<br/>
-<br/>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests', action='list')}">
- <span>Browse requests</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- <div class="toolFormTitle">Edit request "${request.name}"</div>
- %if len(select_request_type.options) == 1:
- There are no request types created for a new request.
- %else:
- <div class="toolFormBody">
- <form name="edit_request" id="edit_request" action="${h.url_for( controller='requests', action='edit', request_id=request.id)}" method="post" >
- <div class="form-row">
- <label>
- Select Request Type:
- </label>
- ${select_request_type.get_html()}
- </div>
-
- %if select_request_type.get_selected() != ('Select one', 'none'):
- %for i, field in enumerate(widgets):
- <div class="form-row">
- <label>${field['label']}</label>
- ${field['widget'].get_html()}
- %if field['label'] == 'Data library' and new_library:
- ${new_library.get_html()}
- %endif
- <div class="toolParamHelp" style="clear: both;">
- ${field['helptext']}
- </div>
- <div style="clear: both"></div>
- </div>
- %endfor
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="save_changes_request_button" value="Save changes"/>
- ##<input type="submit" name="edit_samples_button" value="Edit samples"/>
- </div>
- %endif
- </form>
- </div>
-</div>
-%endif
--- a/templates/requests/new_request.mako
+++ /dev/null
@@ -1,94 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#new_request" ).submit();
- }
- });
-});
-</script>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
-</%def>
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "autocomplete_tagging" )}
-</%def>
-
-<br/>
-<br/>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests', action='list')}">
- <span>Browse requests</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- <div class="toolFormTitle">Add a new request</div>
- %if len(select_request_type.options) == 1:
- There are no request types created for a new request.
- %else:
- <div class="toolFormBody">
- <form name="new_request" id="new_request" action="${h.url_for( controller='requests', action='new', create=True )}" method="post" >
- <div class="form-row">
- <label>
- Select Request Type:
- </label>
- ${select_request_type.get_html()}
- </div>
-
- %if select_request_type.get_selected() != ('Select one', 'none'):
- %for i, field in enumerate(widgets):
- <div class="form-row">
- <label>${field['label']}</label>
- ${field['widget'].get_html()}
- ##%if field['label'] == 'Data library' and new_library:
- ## ${new_library.get_html()}
- ##%endif
- <div class="toolParamHelp" style="clear: both;">
- ${field['helptext']}
- </div>
- <div style="clear: both"></div>
- </div>
- %endfor
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="create_request_button" value="Save"/>
- <input type="submit" name="create_request_samples_button" value="Add samples"/>
- </div>
- %endif
- </form>
- </div>
-</div>
-%endif
--- /dev/null
+++ b/templates/requests/common/index.mako
@@ -0,0 +1,16 @@
+<%inherit file="/webapps/galaxy/base_panels.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="requests"
+ self.message_box_visible=False
+%>
+</%def>
+
+<%def name="center_panel()">
+
+ <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="requests", action="list" )}"></iframe>
+
+</%def>
--- a/templates/sample/index.mako
+++ /dev/null
@@ -1,16 +0,0 @@
-<%inherit file="/webapps/galaxy/base_panels.mako"/>
-
-<%def name="init()">
-<%
- self.has_left_panel=False
- self.has_right_panel=False
- self.active_view="requests"
-
-%>
-</%def>
-
-<%def name="center_panel()">
-
- <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="sample", action="list", request_id=request_id )}"></iframe>
-
-</%def>
--- a/templates/requests/show_request.mako
+++ /dev/null
@@ -1,430 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#show_request" ).submit();
- }
- });
-});
-</script>
-
-
-<script type="text/javascript">
-$(document).ready(function(){
- //hide the all of the element with class msg_body
- $(".msg_body").hide();
- //toggle the componenet with class msg_body
- $(".msg_head").click(function(){
- $(this).next(".msg_body").slideToggle(450);
- });
-});
-</script>
-<style type="text/css">
-.msg_head {
- padding: 0px 0px;
- cursor: pointer;
-}
-
-}
-</style>
-
-%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', action='list', operation='Submit', id=trans.security.encode_id(request.id) )}">
- <span>Submit request</span></a>
- </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>
-</ul>
-
-<%def name="show_basic_info_form( sample_index, sample, info )">
- <td>
- <input type="text" name=sample_${sample_index}_name value="${info['name']}" size="10"/>
- <div class="toolParamHelp" style="clear: both;">
- <i>${' (required)' }</i>
- </div>
- </td>
- %if sample:
- %if sample.request.unsubmitted():
- <td></td>
- %else:
- <td><input type="text" name=sample_${sample_index}_barcode value="${info['barcode']}" size="10"/></td>
- %endif
- %else:
- <td></td>
- %endif
- %if sample:
- %if not sample.current_state():
- <td>Unsubmitted</td>
- %else:
- <td><a href="${h.url_for( controller='requests_admin', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a></td>
- %endif
- %else:
- <td></td>
- %endif
- <td>${info['lib_widget'].get_html()}</td>
- <td>${info['folder_widget'].get_html()}</td>
- %if request.submitted() or request.complete():
- %if sample:
- <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">${len(sample.dataset_files)}</a></td>
- %else:
- <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">Add</a></td>
- %endif
- %endif
-</%def>
-
-## This function displays the "Basic Information" grid
-<%def name="render_basic_info_grid()">
- <h4>Sample Information</h4>
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- <th>Barcode</th>
- <th>State</th>
- <th>Data Library</th>
- <th>Folder</th>
- %if request.submitted() or request.complete():
- <th>Dataset(s) Transferred</th>
- %endif
- <th></th>
- </tr>
- <thead>
- <tbody>
- <%
- trans.sa_session.refresh( request )
- %>
- %for sample_index, info in enumerate(current_samples):
- <%
- if sample_index in range(len(request.samples)):
- sample = request.samples[sample_index]
- else:
- sample = None
- %>
- %if edit_mode == 'True':
- <tr>
- ${show_basic_info_form( sample_index, sample, info )}
- </tr>
- %else:
- <tr>
- %if sample_index in range(len(request.samples)):
- <td>${info['name']}</td>
- <td>${info['barcode']}</td>
- <td>
- %if sample.current_state():
- <a href="${h.url_for( controller='requests', action='show_events', sample_id=sample.id)}">${sample.current_state().name}</a>
- %else:
- Unsubmitted
- %endif
- </td>
- %if info['library']:
- <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( info['library'].id ) )}">${info['library'].name}</a></td>
- %else:
- <td></td>
- %endif
- %if info['folder']:
- <td>${info['folder'].name}</td>
- %else:
- <td></td>
- %endif
- %if request.submitted() or request.complete():
- <td>
- <a href="${h.url_for( controller='requests', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">${len(sample.dataset_files)}</a>
- </td>
- %endif
-
-
- %else:
- ${show_basic_info_form( sample_index, sample, info )}
- %endif
- %if request.unsubmitted() or request.rejected():
- <td>
- %if sample:
- %if sample.request.unsubmitted():
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='delete_sample', request_id=request.id, sample_id=sample_index )}">
- <img src="${h.url_for('/static/images/delete_icon.png')}" />
- <span></span></a>
- %endif
- %endif
- </td>
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
-</%def>
-
-<%def name="render_sample_form( index, sample_name, sample_values, fields_dict )">
- <td>
- ${sample_name}
- </td>
- %for field_index, field in fields_dict.items():
- <td>
- %if field['type'] == 'TextField':
- <input type="text" name="sample_${index}_field_${field_index}" value="${sample_values[field_index]}" size="7"/>
- %elif field['type'] == 'SelectField':
- <select name="sample_${index}_field_${field_index}" last_selected_value="2">
- %for option_index, option in enumerate(field['selectlist']):
- %if option == sample_values[field_index]:
- <option value="${option}" selected>${option}</option>
- %else:
- <option value="${option}">${option}</option>
- %endif
- %endfor
- </select>
- %elif field['type'] == 'WorkflowField':
- <select name="sample_${index}_field_${field_index}">
- %if str(sample_values[field_index]) == 'none':
- <option value="none" selected>Select one</option>
- %else:
- <option value="none">Select one</option>
- %endif
- %for option_index, option in enumerate(request.user.stored_workflows):
- %if not option.deleted:
- %if str(option.id) == str(sample_values[field_index]):
- <option value="${option.id}" selected>${option.name}</option>
- %else:
- <option value="${option.id}">${option.name}</option>
- %endif
- %endif
- %endfor
- </select>
- %elif field['type'] == 'CheckboxField':
- <input type="checkbox" name="sample_${index}_field_${field_index}" value="Yes"/>
- %endif
- <div class="toolParamHelp" style="clear: both;">
- <i>${'('+field['required']+')' }</i>
- </div>
- </td>
- %endfor
-</%def>
-
-<%def name="render_sample( index, sample_name, sample_values, fields_dict )">
- <td>
- ${sample_name}
- </td>
- %for field_index, field in fields_dict.items():
- <td>
- %if sample_values[field_index]:
- %if field['type'] == 'WorkflowField':
- %if str(sample_values[field_index]) != 'none':
- <% workflow = trans.sa_session.query( trans.app.model.StoredWorkflow ).get( int(sample_values[field_index]) ) %>
- <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
- %endif
- %else:
- ${sample_values[field_index]}
- %endif
- %else:
- <i>None</i>
- %endif
-
- </td>
- %endfor
-</%def>
-
-<%def name="render_grid( grid_index, grid_name, fields_dict )">
- <br/>
- <div class="msg_list">
- %if grid_name:
- <h4 class="msg_head"><u>${grid_name}</u></h4>
- %else:
- <h4>Grid ${grid_index}</h4>
- %endif
- %if edit_mode == 'False' or len(current_samples) <= len(request.samples):
- <div class="msg_body">
- %else:
- <div class="msg_body2">
- %endif
- <table class="grid">
- <thead>
- <tr>
- <th>Name</th>
- %for index, field in fields_dict.items():
- <th>
- ${field['label']}
- <div class="toolParamHelp" style="clear: both;">
- <i>${field['helptext']}</i>
- </div>
- </th>
- %endfor
- <th></th>
- </tr>
- <thead>
- <tbody>
- <%
- trans.sa_session.refresh( request )
- %>
- %for sample_index, sample in enumerate(current_samples):
- %if edit_mode == 'True':
- <tr>
- ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
- </tr>
- %else:
- <tr>
- %if sample_index in range(len(request.samples)):
- ${render_sample( sample_index, sample['name'], sample['field_values'], fields_dict )}
- %else:
- ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
- %endif
- </tr>
- %endif
- %endfor
- </tbody>
- </table>
- </div>
- </div>
-</%def>
-
-<div class="toolForm">
- <form id="request_details" name="request_details" >
- <div class="form-row">
- <div class="msg_list">
- <h4 class="msg_head"><u>Request Information</u></h4>
- <div class="msg_body">
- %for index, rd in enumerate(request_details):
- <div class="form-row">
- <label>${rd['label']}</label>
- %if not rd['value']:
- <i>None</i>
- %else:
- %if 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
- %endif
- </div>
- <div style="clear: both"></div>
- %endfor
- <div class="form-row">
- <ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='Edit', id=trans.security.encode_id(request.id))}">
- <span>Edit request details</span></a>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </form>
- <form id="show_request" name="show_request" action="${h.url_for( controller='requests', action='show_request', edit_mode=edit_mode )}" enctype="multipart/form-data" method="post" >
- <div class="form-row">
- %if current_samples:
- ## first render the basic info grid
- ${render_basic_info_grid()}
- ## then render the other grid(s)
- <% trans.sa_session.refresh( request.type.sample_form ) %>
- %for grid_index, grid_name in enumerate(request.type.sample_form.layout):
- ${render_grid( grid_index, grid_name, request.type.sample_form.fields_of_grid( grid_index ) )}
- <br/>
- %endfor
- %else:
- <label>There are no samples.</label>
- %endif
- </div>
- %if request.unsubmitted() and edit_mode == 'False':
- <table class="grid">
- <tbody>
- <tr>
- <div class="form-row">
- <td>
- %if current_samples:
- <label>Copy </label>
- <input type="integer" name="num_sample_to_copy" value="1" size="3"/>
- <label>sample(s) from sample</label>
- ${sample_copy.get_html()}
- %endif
- <input type="submit" name="add_sample_button" value="Add New"/>
- </td>
- <td>
- %if len(current_samples) and len(current_samples) <= len(request.samples):
- <input type="submit" name="edit_samples_button" value="Edit samples"/>
- %endif
- </td>
- </div>
- </tr>
- </tbody>
- </table>
- %endif
- %if request.unsubmitted() and (request.samples or current_samples):
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="save_samples_button" value="Save"/>
- %if edit_mode == 'True':
- <input type="submit" name="cancel_changes_button" value="Cancel"/>
- %endif
- </div>
- %endif
- <input type="hidden" name="request_id" value="${request.id}" />
- </form>
-</div>
-
-
-<br/>
-%if request.unsubmitted():
-<div class="toolForm">
- <form id="show_request" name="show_request" action="${h.url_for( controller='requests', action='show_request', edit_mode=edit_mode )}" enctype="multipart/form-data" method="post" >
- <div class="form-row">
- <div class="msg_list">
- <h4 class="msg_head"><u>Import samples from csv file</u></h4>
- <div class="msg_body">
- <input type="file" name="file_data" />
- <input type="submit" name="import_samples_button" value="Import samples"/>
- <br/>
- <div class="toolParamHelp" style="clear: both;">
- The csv file must be in the following format:<br/>
- SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...
- </div>
- </div>
- </div>
- </div>
- <input type="hidden" name="request_id" value="${request.id}" />
- </form>
-</div>
-%endif
--- /dev/null
+++ b/templates/requests/common/new_request.mako
@@ -0,0 +1,91 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<script type="text/javascript">
+$( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#new_request" ).submit();
+ }
+ });
+});
+</script>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
+</%def>
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ${h.css( "autocomplete_tagging" )}
+</%def>
+
+<br/>
+<br/>
+<ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, cntrller=cntrller, action='list')}">
+ <span>Browse requests</span></a>
+ </li>
+</ul>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Add a new request</div>
+ %if len(select_request_type.options) == 1:
+ There are no request types created for a new request.
+ %else:
+ <div class="toolFormBody">
+ <form name="new_request" id="new_request" action="${h.url_for( controller='requests_common', action='new', cntrller=cntrller)}" method="post" >
+ <div class="form-row">
+ <label>
+ Select request type
+ </label>
+ ${select_request_type.get_html()}
+ </div>
+
+ %if select_request_type.get_selected() != ('Select one', 'none'):
+ %for i, field in enumerate(widgets):
+ <div class="form-row">
+ <label>${field['label']}</label>
+ ${field['widget'].get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ ${field['helptext']}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %endfor
+ <div class="form-row">
+ <input type="submit" name="create_request_button" value="Save"/>
+ <input type="submit" name="create_request_samples_button" value="Add samples"/>
+ </div>
+ %endif
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="refresh" value="true" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ </form>
+ </div>
+</div>
+%endif
--- a/templates/admin/requests/get_data.mako
+++ /dev/null
@@ -1,227 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$(document).ready(function(){
- //hide the all of the element with class msg_body
- $(".msg_body").hide();
- //toggle the componenet with class msg_body
- $(".msg_head").click(function(){
- $(this).next(".msg_body").slideToggle(450);
- });
-});
-
-
-
-
-</script>
-
-<script type="text/javascript">
- function display_file_details(sample_id, folder_path)
- {
- var w = document.get_data.files_list.selectedIndex;
- var selected_value = document.get_data.files_list.options[w].value;
- var cell = $("#file_details");
- if(selected_value.charAt(selected_value.length-1) != '/')
- {
- // Make ajax call
- $.ajax( {
- type: "POST",
- url: "${h.url_for( controller='requests_admin', action='get_file_details' )}",
- dataType: "json",
- data: { id: sample_id, folder_path: document.get_data.folder_path.value+selected_value },
- success : function ( data ) {
- cell.html( '<label>'+data+'</label>' )
- }
- });
- }
- else
- {
- cell.html( '' )
- }
-
-
- }
-</script>
-
-<script type="text/javascript">
- function open_folder1(sample_id, folder_path)
- {
- var w = document.get_data.files_list.selectedIndex;
- var selected_value = document.get_data.files_list.options[w].value;
- var cell = $("#file_details");
- if(selected_value.charAt(selected_value.length-1) == '/')
- {
- document.get_data.folder_path.value = document.get_data.folder_path.value+selected_value
- // Make ajax call
- $.ajax( {
- type: "POST",
- url: "${h.url_for( controller='requests_admin', action='open_folder' )}",
- dataType: "json",
- data: { id: sample_id, folder_path: document.get_data.folder_path.value },
- success : function ( data ) {
- document.get_data.files_list.options.length = 0
- for(i=0; i<data.length; i++)
- {
- var newOpt = new Option(data[i], data[i]);
- document.get_data.files_list.options[i] = newOpt;
- }
- //cell.html( '<label>'+data+'</label>' )
-
- }
- });
- }
- else
- {
- cell.html( '' )
- }
- }
-</script>
-
-
-<style type="text/css">
-.msg_head {
- padding: 0px 0px;
- cursor: pointer;
-}
-
-}
-</style>
-
-
-<h2>Data transfer from Sequencer</h2>
-<h3>Sample "${sample.name}" of Request "${sample.request.name}"</h3>
-<br/>
-<br/>
-
-<ul class="manage-table-actions">
- %if sample.request.submitted() and sample.inprogress_dataset_files():
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">
- <span>Refresh this page</span></a>
- </li>
- %endif
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_request_types', operation='view', id=trans.security.encode_id(sample.request.type.id) )}">
- <span>Sequencer information</span></a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller='library_admin', id=trans.security.encode_id( sample.library.id ) )}">
- <span>${sample.library.name} Data Library</span></a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='show_request', id=trans.security.encode_id(sample.request.id) )}">
- <span>Browse this request</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- %if len(dataset_files):
-## <form name="get_data" action="${h.url_for( controller='requests_admin', action='get_data', sample_id=sample.id)}" method="post" >
- <div class="form-row">
- <h4>Sample Dataset(s)</h4>
- %if sample.untransferred_dataset_files():
- <div class="form-row">
- <ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', start_transfer_button=True, sample_id=sample.id )}">
- <span>Start transfer</span></a>
- </li>
- </ul>
- </div>
- %endif
- <div class="form-row">
- <table class="grid">
- <thead>
- <tr>
- <th>Dataset File</th>
- <th>Transfer Status</th>
- <th></th>
- </tr>
- <thead>
- <tbody>
- %for dataset_index, dataset_file in enumerate(dataset_files):
- ${sample_dataset_files( dataset_index, dataset_file['name'], dataset_file['status'] )}
- %endfor
- </tbody>
- </table>
- </div>
- </div>
-
-## </form>
-##</div>
-
-
-<br/>
-<br/>
-%endif
-
-##<div class="toolForm">
- <form name="get_data" id="get_data" action="${h.url_for( controller='requests_admin', action='get_data', sample_id=sample.id)}" method="post" >
- <div class="form-row">
- ##<div class="toolFormTitle">Select files for transfer</div>
- <h4>Select files for transfer</h4>
- <div style="width: 60%;">
- <div class="form-row">
- <label>Folder path on the sequencer:</label>
- <input type="text" name="folder_path" value="${folder_path}" size="100"/>
- <input type="submit" name="browse_button" value="List contents"/>
- ##<input type="submit" name="open_folder" value="Open folder"/>
- <input type="submit" name="folder_up" value="Up"/>
- </div>
- <div class="form-row">
- <select name="files_list" id="files_list" style="max-width: 98%; width: 98%; height: 150px; font-size: 100%;" ondblclick="open_folder1(${sample.id}, '${folder_path}')" onChange="display_file_details(${sample.id}, '${folder_path}')" multiple>
- %for index, f in enumerate(files):
- <option value="${f}">${f}</option>
- %endfor
- </select>
- <br/>
- <div id="file_details" class="toolParamHelp" style="clear: both;">
-
- </div>
- </div>
- <div class="form-row">
- <div class="toolParamHelp" style="clear: both;">
- After selecting dataset(s), be sure to click on the <b>Start transfer</b> button.
- Once the transfer is complete the dataset(s) will show up on this page.
- </div>
- <input type="submit" name="select_files_button" value="Select"/>
- </div>
- </div>
- </div>
- </form>
-</div>
-
-<%def name="sample_dataset_files( dataset_index, dataset_name, status )">
- <tr>
- <td>
- <label class="msg_head"><a href="${h.url_for( controller='requests_admin', action='dataset_details', sample_id=trans.security.encode_id(sample.id), dataset_index=dataset_index )}">${dataset_name}</a></label>
-## <div class="msg_head"><u>${dataset_file.split('/')[-1]}</u></div>
-## <div class="msg_body">
-## ${dataset_file}
-## </div>
- </td>
- <td>
- %if status not in [sample.transfer_status.NOT_STARTED, sample.transfer_status.COMPLETE]:
- <i>${status}</i>
- %else:
- ${status}
- %endif
- </td>
- ##<td></td>
- %if status == sample.transfer_status.NOT_STARTED:
- <td>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', sample_id=sample.id, remove_dataset_button=True, dataset_index=dataset_index )}">
- <img src="${h.url_for('/static/images/delete_icon.png')}" />
- <span></span></a>
- </td>
- %else:
- <td></td>
- %endif
- </tr>
-</%def>
--- a/templates/admin/requests/add_states.mako
+++ /dev/null
@@ -1,26 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<div class="toolForm">
- <div class="toolFormTitle">Create ${num_states} states for the '${request_type_name}' request type</div>
- <form name="new_form_fields" action="${h.url_for( controller='requests_admin', action='request_type', name=request_type_name, description=desc, num_states=num_states, request_form_id=request_form_id, sample_form_id=sample_form_id)}" method="post" >
- <div class="toolFormBody">
- %for element_count in range( num_states ):
- <div class="form-row">
- <label>${1+element_count}) State name:</label>
- <input type="text" name="state_name_${element_count}" value="" size="40"/>
- <label>State help text (optional):</label>
- <input type="text" name="state_desc_${element_count}" value="" size="40"/>
- </div>
- <div style="clear: both"></div>
- %endfor
- </div>
- <div class="form-row">
- <input type="submit" name="save_request_type" value="Save"/>
- </div>
- </form>
-</div>
--- /dev/null
+++ b/templates/requests/common/edit_request.mako
@@ -0,0 +1,84 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<script type="text/javascript">
+$( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#edit_request" ).submit();
+ }
+ });
+});
+</script>
+
+<br/>
+<br/>
+<ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, cntrller=cntrller, action='list')}">
+ <span>Browse requests</span></a>
+ </li>
+</ul>
+
+<div class="toolForm">
+ <div class="toolFormTitle">Edit request "${request.name}"</div>
+ %if len(select_request_type.options) == 1:
+ There are no request types created for a new request.
+ %else:
+ <div class="toolFormBody">
+ <form name="edit_request" id="edit_request" action="${h.url_for( controller='requests_common', cntrller=cntrller, action='edit', id=trans.security.encode_id(request.id))}" method="post" >
+ <div class="form-row">
+ <label>
+ Select Request Type:
+ </label>
+ ${select_request_type.get_html()}
+ </div>
+
+ %if select_request_type.get_selected() != ('Select one', 'none'):
+ %for i, field in enumerate(widgets):
+ <div class="form-row">
+ <label>${field['label']}</label>
+ ${field['widget'].get_html()}
+ %if field['label'] == 'Data library' and new_library:
+ ${new_library.get_html()}
+ %endif
+ <div class="toolParamHelp" style="clear: both;">
+ ${field['helptext']}
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %endfor
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="refresh" value="true" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="save_changes_request_button" value="Save changes"/>
+ ##<input type="submit" name="edit_samples_button" value="Edit samples"/>
+ </div>
+ %endif
+ </form>
+ </div>
+</div>
+%endif
--- a/lib/galaxy/web/controllers/requests.py
+++ b/lib/galaxy/web/controllers/requests.py
@@ -84,7 +84,7 @@ class RequestsGrid( grids.Grid ):
NameColumn( "Name",
key="name",
model_class=model.Request,
- link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="show", id=item.id ) ) ),
attach_popup=True,
filterable="advanced" ),
DescriptionColumn( "Description",
@@ -92,7 +92,7 @@ class RequestsGrid( grids.Grid ):
model_class=model.Request,
filterable="advanced" ),
SamplesColumn( "Sample(s)",
- link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="show", id=item.id ) ) ), ),
TypeColumn( "Type" ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
grids.DeletedColumn( "Deleted",
@@ -120,7 +120,8 @@ class RequestsGrid( grids.Grid ):
]
global_actions = [
- grids.GridAction( "Create new request", dict( controller='requests',
+ grids.GridAction( "Create new request", dict( controller='requests_common',
+ cntrller='requests',
action='new',
select_request_type='True' ) )
]
@@ -149,18 +150,36 @@ class Requests( BaseController ):
action='list',
status='error',
message="Invalid request ID") )
- if operation == "show_request":
- return self.__show_request( trans, **kwd )
+ if operation == "show":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='show',
+ **kwd ) )
elif operation == "submit":
- return self.__submit_request( trans, **kwd )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='submit',
+ **kwd ) )
elif operation == "delete":
- return self.__delete_request( trans, **kwd )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='delete',
+ **kwd ) )
elif operation == "undelete":
- return self.__undelete_request( trans, **kwd )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='undelete',
+ **kwd ) )
elif operation == "edit":
- return self.__edit_request( trans, **kwd )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='edit',
+ show=True, **kwd ) )
elif operation == "events":
- return self.__request_events( trans, **kwd )
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests',
+ action='events',
+ **kwd ) )
# if there are one or more requests that has been rejected by the admin
# recently, then show a message as a reminder to the user
rlist = trans.sa_session.query( trans.app.model.Request ) \
@@ -176,915 +195,4 @@ class Requests( BaseController ):
% rejected
# Render the list view
return self.request_grid( trans, **kwd )
- def __request_events(self, trans, **kwd):
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message,
- **kwd) )
- events_list = []
- all_events = request.events
- for event in all_events:
- events_list.append((event.state, time_ago(event.update_time), 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
- '''
- request = trans.sa_session.query( trans.app.model.Request ).get( id )
- # list of widgets to be rendered on the request form
- request_details = []
- # main details
- request_details.append(dict(label='Description',
- value=request.desc,
- helptext=''))
- request_details.append(dict(label='Type',
- value=request.type.name,
- helptext=''))
-
- request_details.append(dict(label='State',
- value=request.state(),
- helptext=''))
- request_details.append(dict(label='Date created',
- value=request.create_time,
- helptext=''))
- # form fields
- for index, field in enumerate(request.type.request_form.fields):
- if field['required']:
- req = 'Required'
- else:
- req = 'Optional'
- if field['type'] == 'AddressField':
- if request.values.content[index]:
- request_details.append(dict(label=field['label'],
- value=trans.sa_session.query( trans.app.model.UserAddress ).get( int( request.values.content[index] ) ).get_html(),
- helptext=field['helptext']+' ('+req+')'))
- else:
- request_details.append(dict(label=field['label'],
- value=None,
- helptext=field['helptext']+' ('+req+')'))
-
- else:
- request_details.append(dict(label=field['label'],
- value=request.values.content[index],
- helptext=field['helptext']+' ('+req+')'))
- if request.notify:
- notify = 'Yes'
- else:
- notify = 'No'
- request_details.append(dict(label='Send email notification once the sequencing request is complete',
- value=notify,
- helptext=''))
- return request_details
- def __show_request(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- add_sample = params.get('add_sample', False)
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
- except:
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message="Invalid request ID") )
- # get all data libraries accessible to this user
- libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
- current_samples = []
- for i, s in enumerate(request.samples):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
- current_samples.append(dict(name=s.name,
- barcode=s.bar_code,
- library=s.library,
- folder=s.folder,
- dataset_files=s.dataset_files,
- field_values=s.values.content,
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- if add_sample:
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples)+1,
- libraries, None, **kwd)
- current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
- barcode='',
- library=None,
- folder=None,
- dataset_files=[],
- field_values=['' for field in request.type.sample_form.fields],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details='hide', edit_mode=util.restore_text( params.get( 'edit_mode', 'False' ) ),
- message=message, status=status )
- def __library_widgets(self, trans, user, sample_index, libraries, sample=None, lib_id=None, folder_id=None, **kwd):
- '''
- This method creates the data library & folder selectbox for creating &
- editing samples. First we get a list of all the libraries accessible to
- the current user and display it in a selectbox. If the user has selected an
- existing library then display all the accessible sub folders of the selected
- data library.
- '''
- params = util.Params( kwd )
- # data library selectbox
- if not lib_id:
- lib_id = params.get( "sample_%i_library_id" % sample_index, 'none' )
- selected_lib = None
- if sample and lib_id == 'none':
- if sample.library:
- lib_id = str(sample.library.id)
- selected_lib = sample.library
- # create data library selectbox with refresh on change enabled
- lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
- lib_widget = SelectField( "sample_%i_library_id" % sample_index,
- refresh_on_change=True,
- refresh_on_change_values=lib_id_list )
- # fill up the options in the Library selectbox
- # first option 'none' is the value for "Select one" option
- if lib_id == 'none':
- lib_widget.add_option('Select one', 'none', selected=True)
- else:
- lib_widget.add_option('Select one', 'none')
- # all the libraries available to the selected user
- for lib, hidden_folder_ids in libraries.items():
- if str(lib.id) == str(lib_id):
- lib_widget.add_option(lib.name, lib.id, selected=True)
- selected_lib, selected_hidden_folder_ids = lib, hidden_folder_ids.split(',')
- else:
- lib_widget.add_option(lib.name, lib.id)
- lib_widget.refresh_on_change_values.append(lib.id)
- # create the folder selectbox
- folder_widget = SelectField( "sample_%i_folder_id" % sample_index )
- # when editing a request, either the user has already selected a subfolder or not
- if sample:
- if sample.folder:
- current_fid = sample.folder.id
- else:
- # when a folder not yet associated with the request then the
- # the current folder is set to the root_folder of the
- # parent data library if present.
- if sample.library:
- current_fid = sample.library.root_folder.id
- else:
- current_fid = params.get( "sample_%i_folder_id" % sample_index, 'none' )
- else:
- if folder_id:
- current_fid = folder_id
- else:
- current_fid = 'none'
- # first option
- if lib_id == 'none':
- folder_widget.add_option('Select one', 'none', selected=True)
- else:
- folder_widget.add_option('Select one', 'none')
- if selected_lib:
- # get all show-able folders for the selected library
- showable_folders = trans.app.security_agent.get_showable_folders( user, user.all_roles(),
- selected_lib,
- [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ],
- selected_hidden_folder_ids )
- for f in showable_folders:
- if str(f.id) == str(current_fid):
- folder_widget.add_option(f.name, f.id, selected=True)
- else:
- folder_widget.add_option(f.name, f.id)
- return lib_widget, folder_widget
- def __update_samples(self, trans, request, **kwd):
- '''
- This method retrieves all the user entered sample information and
- returns an list of all the samples and their field values
- '''
- params = util.Params( kwd )
- details = params.get( 'details', 'hide' )
- edit_mode = params.get( 'edit_mode', 'False' )
- # get all data libraries accessible to this user
- libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
-
- current_samples = []
- for i, s in enumerate(request.samples):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
- current_samples.append(dict(name=s.name,
- barcode=s.bar_code,
- library=s.library,
- folder=s.folder,
- field_values=s.values.content,
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- if edit_mode == 'False':
- sample_index = len(request.samples)
- else:
- sample_index = 0
- while True:
- lib_id = None
- folder_id = None
- if params.get( 'sample_%i_name' % sample_index, '' ):
- # data library
- try:
- library = trans.sa_session.query( trans.app.model.Library ).get( int( params.get( 'sample_%i_library_id' % sample_index, None ) ) )
- lib_id = library.id
- except:
- library = None
- # folder
- try:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( int( params.get( 'sample_%i_folder_id' % sample_index, None ) ) )
- folder_id = folder.id
- except:
- if library:
- folder = library.root_folder
- else:
- folder = None
- sample_info = dict( name=util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ),
- barcode=util.restore_text( params.get( 'sample_%i_barcode' % sample_index, '' ) ),
- library=library,
- folder=folder)
- sample_info['field_values'] = []
- for field_index in range(len(request.type.sample_form.fields)):
- sample_info['field_values'].append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) ))
- if edit_mode == 'False':
- sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans,
- request.user,
- sample_index,
- libraries,
- None, lib_id, folder_id, **kwd)
- current_samples.append(sample_info)
- else:
- sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans,
- request.user,
- sample_index,
- libraries,
- request.samples[sample_index],
- **kwd)
- current_samples[sample_index] = sample_info
- sample_index = sample_index + 1
- else:
- break
- return current_samples, details, edit_mode, libraries
- def __copy_sample(self, current_samples):
- copy_list = SelectField('copy_sample')
- copy_list.add_option('None', -1, selected=True)
- for i, s in enumerate(current_samples):
- copy_list.add_option(s['name'], i)
- return copy_list
- def __import_samples(self, trans, request, current_samples, details, libraries, **kwd):
- '''
- This method reads the samples csv file and imports all the samples
- The format of the csv file is:
- SampleName,DataLibrary,DataLibraryFolder,Field1,Field2....
- '''
- try:
- params = util.Params( kwd )
- edit_mode = params.get( 'edit_mode', 'False' )
- file_obj = params.get('file_data', '')
- reader = csv.reader(file_obj.file)
- for row in reader:
- lib_id = None
- folder_id = None
- lib = trans.sa_session.query( trans.app.model.Library ) \
- .filter( and_( trans.app.model.Library.table.c.name==row[1], \
- trans.app.model.Library.table.c.deleted==False ) )\
- .first()
- if lib:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ) \
- .filter( and_( trans.app.model.LibraryFolder.table.c.name==row[2], \
- trans.app.model.LibraryFolder.table.c.deleted==False ) )\
- .first()
- if folder:
- lib_id = lib.id
- folder_id = folder.id
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, len(current_samples),
- libraries, None, lib_id, folder_id, **kwd)
- current_samples.append(dict(name=row[0],
- barcode='',
- library=None,
- folder=None,
- lib_widget=lib_widget,
- folder_widget=folder_widget,
- field_values=row[3:]))
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- except:
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- operation='show_request',
- id=trans.security.encode_id(request.id),
- status='error',
- message='Error in importing samples file' ))
-
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def show_request(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', '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',
- action='list',
- status='error',
- message="Invalid request ID",
- **kwd) )
- # get the user entered sample details
- current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd )
- if params.get('import_samples_button', False) == 'Import samples':
- return self.__import_samples(trans, request, current_samples, details, libraries, **kwd)
- elif params.get('add_sample_button', False) == 'Add New':
- # add an empty or filled sample
- # if the user has selected a sample no. to copy then copy the contents
- # of the src sample to the new sample else an empty sample
- src_sample_index = int(params.get( 'copy_sample', -1 ))
- # get the number of new copies of the src sample
- num_sample_to_copy = int(params.get( 'num_sample_to_copy', 1 ))
- if src_sample_index == -1:
- for ns in range(num_sample_to_copy):
- # empty sample
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples),
- libraries, None, **kwd)
- current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
- barcode='',
- library=None,
- folder=None,
- field_values=['' for field in request.type.sample_form.fields],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- else:
- src_library_id = current_samples[src_sample_index]['lib_widget'].get_selected()[1]
- src_folder_id = current_samples[src_sample_index]['folder_widget'].get_selected()[1]
- for ns in range(num_sample_to_copy):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples),
- libraries, sample=None,
- lib_id=src_library_id,
- folder_id=src_folder_id,
- **kwd)
- current_samples.append(dict(name=current_samples[src_sample_index]['name']+'_%i' % (len(current_samples)+1),
- barcode='',
- library_id='none',
- folder_id='none',
- field_values=[val for val in current_samples[src_sample_index]['field_values']],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- elif params.get('save_samples_button', False) == 'Save':
- # check for duplicate sample names
- message = ''
- for index in range(len(current_samples)-len(request.samples)):
- sample_index = index + len(request.samples)
- sample_name = current_samples[sample_index]['name']
- if not sample_name.strip():
- message = 'Please enter the name of sample number %i' % sample_index
- break
- count = 0
- for i in range(len(current_samples)):
- if sample_name == current_samples[i]['name']:
- count = count + 1
- if count > 1:
- message = "This request has <b>%i</b> samples with the name <b>%s</b>.\nSamples belonging to a request must have unique names." % (count, sample_name)
- break
- if message:
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples = current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, edit_mode=edit_mode,
- status='error', message=message)
- # save all the new/unsaved samples entered by the user
- if edit_mode == 'False':
- for index in range(len(current_samples)-len(request.samples)):
- sample_index = len(request.samples)
- form_values = trans.app.model.FormValues(request.type.sample_form,
- current_samples[sample_index]['field_values'])
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- s = trans.app.model.Sample(current_samples[sample_index]['name'], '',
- request, form_values,
- current_samples[sample_index]['barcode'],
- current_samples[sample_index]['library'],
- current_samples[sample_index]['folder'],
- dataset_files=[])
- trans.sa_session.add( s )
- trans.sa_session.flush()
- else:
- status = 'done'
- message = 'Changes made to the sample(s) are saved. '
- for sample_index in range(len(current_samples)):
- sample = request.samples[sample_index]
- sample.name = current_samples[sample_index]['name']
- sample.library = current_samples[sample_index]['library']
- sample.folder = current_samples[sample_index]['folder']
- if request.submitted():
- bc_message = self.__validate_barcode(trans, sample, current_samples[sample_index]['barcode'])
- if bc_message:
- status = 'error'
- message += bc_message
- else:
- sample.bar_code = current_samples[sample_index]['barcode']
- trans.sa_session.add( sample )
- trans.sa_session.flush()
- form_values = trans.sa_session.query( trans.app.model.FormValues ).get( sample.values.id )
- form_values.content = current_samples[sample_index]['field_values']
- trans.sa_session.add( form_values )
- 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),
- status=status,
- message=message ))
- elif params.get('edit_samples_button', False) == 'Edit samples':
- edit_mode = 'True'
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, libraries=libraries,
- edit_mode=edit_mode)
- elif params.get('cancel_changes_button', False) == 'Cancel':
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- operation='show_request',
- id=trans.security.encode_id(request.id)) )
- else:
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, libraries=libraries,
- edit_mode=edit_mode, status=status, message=message)
-
-
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def delete_sample(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', 0 ) ) )
- current_samples, details, edit_mode = self.__update_samples( request, **kwd )
- sample_index = int(params.get('sample_id', 0))
- sample_name = current_samples[sample_index]['name']
- s = request.has_sample(sample_name)
- if s:
- trans.sa_session.delete( s.values )
- trans.sa_session.delete( s )
- trans.sa_session.flush()
- del current_samples[sample_index]
- return trans.fill_template( '/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples = current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- def __select_request_type(self, trans, rtid):
- requesttype_list = trans.user.accessible_request_types(trans)
- rt_ids = ['none']
- for rt in requesttype_list:
- if not rt.deleted:
- rt_ids.append(str(rt.id))
- select_reqtype = SelectField('select_request_type',
- refresh_on_change=True,
- refresh_on_change_values=rt_ids[1:])
- if rtid == 'none':
- select_reqtype.add_option('Select one', 'none', selected=True)
- else:
- select_reqtype.add_option('Select one', 'none')
- for rt in requesttype_list:
- if not rt.deleted:
- if rtid == rt.id:
- select_reqtype.add_option(rt.name, rt.id, selected=True)
- else:
- select_reqtype.add_option(rt.name, rt.id)
- return select_reqtype
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def new(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- if params.get('select_request_type', False) == 'True':
- return trans.fill_template( '/requests/new_request.mako',
- select_request_type=self.__select_request_type(trans, 'none'),
- widgets=[],
- message=message,
- status=status)
- elif params.get('create', False) == 'True':
- if params.get('create_request_button', False) == 'Save' \
- or params.get('create_request_samples_button', False) == 'Add samples':
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- if not util.restore_text(params.get('name', '')):
- message = 'Please enter the <b>Name</b> of the request'
- kwd['create'] = 'True'
- kwd['status'] = 'error'
- kwd['message'] = message
- kwd['create_request_button'] = None
- kwd['create_request_samples_button'] = None
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='new',
- **kwd) )
- request = self.__save_request(trans, None, **kwd)
- message = 'The new request named <b>%s</b> has been created' % request.name
- if params.get('create_request_button', False) == 'Save':
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- message=message ,
- status='done') )
- elif params.get('create_request_samples_button', False) == 'Add samples':
- new_kwd = {}
- new_kwd['id'] = trans.security.encode_id(request.id)
- new_kwd['operation'] = 'show_request'
- new_kwd['add_sample'] = True
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- message=message ,
- status='done',
- **new_kwd) )
- else:
- return self.__show_request_form(trans, **kwd)
- elif params.get('refresh', False) == 'true':
- return self.__show_request_form(trans, **kwd)
- def __show_request_form(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- try:
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- except:
- return trans.fill_template( '/requests/new_request.mako',
- select_request_type=self.__select_request_type(trans, 'none'),
- widgets=[],
- message=message,
- status=status)
- form_values = None
- select_request_type = self.__select_request_type(trans, request_type.id)
- # list of widgets to be rendered on the request form
- widgets = []
- widgets.append(dict(label='Name of the Experiment',
- widget=TextField('name', 40,
- util.restore_text( params.get( 'name', '' ) )),
- helptext='(Required)'))
- widgets.append(dict(label='Description',
- widget=TextField('desc', 40,
- util.restore_text( params.get( 'desc', '' ) )),
- helptext='(Optional)'))
- widgets = widgets + request_type.request_form.get_widgets( trans.user, **kwd )
- widgets.append(dict(label='Send email notification once the sequencing request is complete',
- widget=CheckboxField('email_notify', False),
- helptext=''))
- return trans.fill_template( '/requests/new_request.mako',
- select_request_type=select_request_type,
- request_type=request_type,
- widgets=widgets,
- message=message,
- status=status)
- def __validate(self, trans, request):
- '''
- Validates the request entered by the user
- '''
- empty_fields = []
- # check rest of the fields of the form
- for index, field in enumerate(request.type.request_form.fields):
- if field['required'] == 'required' and request.values.content[index] in ['', None]:
- empty_fields.append(field['label'])
- if empty_fields:
- message = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name
- for ef in empty_fields:
- message = message + '<b>' +ef + '</b><br/>'
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- operation='edit',
- status = 'error',
- message=message,
- id=trans.security.encode_id(request.id) ))
- # now check the required fields of all the samples of this request
- for s in request.samples:
- for index, field in enumerate(request.type.sample_form.fields):
- if field['required'] == 'required' and s.values.content[index] in ['', None]:
- empty_fields.append((s.name, field['label']))
- if empty_fields:
- message = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name
- for sname, ef in empty_fields:
- message = message + '<b>%s</b> field of sample <b>%s</b><br/>' % (ef, sname)
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- operation='show_request',
- status = 'error',
- message=message,
- id=trans.security.encode_id(request.id) ))
- def __save_request(self, trans, request=None, **kwd):
- '''
- This method saves a new request if request_id is None.
- '''
- params = util.Params( kwd )
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- name = util.restore_text(params.get('name', ''))
- desc = util.restore_text(params.get('desc', ''))
- notify = CheckboxField.is_checked( params.get('email_notify', '') )
- # library
- try:
- library = trans.sa_session.query( trans.app.model.Library ).get( int( params.get( 'library_id', None ) ) )
- except:
- library = None
- try:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( int( params.get( 'folder_id', None ) ) )
- except:
- if library:
- folder = library.root_folder
- else:
- folder = None
- # fields
- values = []
- for index, field in enumerate(request_type.request_form.fields):
- if field['type'] == 'AddressField':
- value = util.restore_text(params.get('field_%i' % index, ''))
- if value == 'new':
- # save this new address in the list of this user's addresses
- user_address = trans.app.model.UserAddress( user=trans.user )
- user_address.desc = util.restore_text(params.get('field_%i_short_desc' % index, ''))
- user_address.name = util.restore_text(params.get('field_%i_name' % index, ''))
- user_address.institution = util.restore_text(params.get('field_%i_institution' % index, ''))
- user_address.address = util.restore_text(params.get('field_%i_address1' % index, ''))+' '+util.restore_text(params.get('field_%i_address2' % index, ''))
- user_address.city = util.restore_text(params.get('field_%i_city' % index, ''))
- user_address.state = util.restore_text(params.get('field_%i_state' % index, ''))
- user_address.postal_code = util.restore_text(params.get('field_%i_postal_code' % index, ''))
- user_address.country = util.restore_text(params.get('field_%i_country' % index, ''))
- user_address.phone = util.restore_text(params.get('field_%i_phone' % index, ''))
- trans.sa_session.add( user_address )
- trans.sa_session.flush()
- trans.sa_session.refresh( trans.user )
- values.append(int(user_address.id))
- elif value == unicode('none'):
- values.append('')
- else:
- values.append(int(value))
- elif field['type'] == 'CheckboxField':
- values.append(CheckboxField.is_checked( params.get('field_%i' % index, '') ))
- else:
- values.append(util.restore_text(params.get('field_%i' % index, '')))
- form_values = trans.app.model.FormValues(request_type.request_form, values)
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- if not request:
- request = trans.app.model.Request(name, desc, request_type,
- trans.user, form_values, notify)
- 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
- request.type = request_type
- request.user = trans.user
- request.values = form_values
- request.notify = notify
- trans.sa_session.add( request )
- trans.sa_session.flush()
- return request
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def edit(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', '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',
- 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', '')):
- message = 'Please enter the <b>Name</b> of the request'
- kwd['status'] = 'error'
- kwd['message'] = message
- kwd['show'] = 'True'
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='edit',
- **kwd) )
- request = self.__save_request(trans, request, **kwd)
- message = 'The changes made to the request named %s has been saved' % request.name
- if params.get('save_changes_request_button', False) == 'Save changes':
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- message=message ,
- status='done') )
- elif params.get('edit_samples_button', False) == 'Edit samples':
- new_kwd = {}
- new_kwd['request_id'] = request.id
- new_kwd['edit_samples_button'] = 'Edit samples'
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='show_request',
- message=message ,
- status='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']) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message) )
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- select_request_type = self.__select_request_type(trans, request.type.id)
- # list of widgets to be rendered on the request form
- widgets = []
- if util.restore_text( params.get( 'name', '' ) ):
- name = util.restore_text( params.get( 'name', '' ) )
- else:
- name = request.name
- widgets.append(dict(label='Name',
- widget=TextField('name', 40, name),
- helptext='(Required)'))
- if util.restore_text( params.get( 'desc', '' ) ):
- desc = util.restore_text( params.get( 'desc', '' ) )
- else:
- desc = request.desc
- widgets.append(dict(label='Description',
- widget=TextField('desc', 40, desc),
- helptext='(Optional)'))
- widgets = widgets + request.type.request_form.get_widgets( trans.user, request.values.content, **kwd )
- widgets.append(dict(label='Send email notification once the sequencing request is complete',
- widget=CheckboxField('email_notify', request.notify),
- helptext=''))
- return trans.fill_template( '/requests/edit_request.mako',
- select_request_type=select_request_type,
- request_type=request.type,
- request=request,
- widgets=widgets,
- message=message,
- status=status)
- return self.__show_request_form(trans)
- def __delete_request(self, trans, **kwd):
- id_list = util.listify( kwd['id'] )
- delete_failed = []
- for id in id_list:
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message,
- **kwd) )
- # a request cannot be deleted once its submitted
- if not request.new():
- delete_failed.append(request.name)
- else:
- request.deleted = True
- trans.sa_session.add( request )
- # delete all the samples belonging to this request
- for s in request.samples:
- s.deleted = True
- trans.sa_session.add( s )
- trans.sa_session.flush()
- if not len(delete_failed):
- message = '%i request(s) has been deleted.' % len(id_list)
- status = 'done'
- else:
- message = '%i request(s) has been deleted. %i request %s could not be deleted as they have been submitted.' % (len(id_list)-len(delete_failed),
- len(delete_failed), str(delete_failed))
- status = 'warning'
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status=status,
- message=message) )
- def __undelete_request(self, trans, **kwd):
- id_list = util.listify( kwd['id'] )
- for id in id_list:
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message,
- **kwd) )
- request.deleted = False
- trans.sa_session.add( request )
- # undelete all the samples belonging to this request
- for s in request.samples:
- s.deleted = False
- trans.sa_session.add( s )
- trans.sa_session.flush()
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='done',
- message='%i request(s) has been undeleted.' % len(id_list) ) )
- def __submit_request(self, trans, **kwd):
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message,
- **kwd) )
- # check if all the required request and its sample fields have been filled
- self.__validate(trans, request)
- # change the request state to 'Submitted'
- comments = "Sequencing request is in progress."
- 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()
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- id=trans.security.encode_id(request.id),
- status='done',
- message='The request <b>%s</b> has been submitted.' % request.name
- ) )
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def show_events(self, trans, **kwd):
- params = util.Params( kwd )
- try:
- sample_id = int(params.get('sample_id', False))
- sample = trans.sa_session.query( trans.app.model.Sample ).get( sample_id )
- except:
- message = "Invalid sample ID"
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message=message,
- **kwd) )
- events_list = []
- all_events = sample.events
- for event in all_events:
- events_list.append((event.state.name, event.state.desc, time_ago(event.update_time), event.comment))
- return trans.fill_template( '/sample/sample_events.mako',
- events_list=events_list,
- sample_name=sample.name,
- request=sample.request)
- #
- # Data transfer from sequencer
- #
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def show_datatx_page( self, trans, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- try:
- sample = trans.sa_session.query( trans.app.model.Sample ).get( trans.security.decode_id( kwd['sample_id'] ) )
- except:
- return trans.response.send_redirect( web.url_for( controller='requests',
- action='list',
- status='error',
- message="Invalid sample ID",
- **kwd) )
- return trans.fill_template( '/requests/show_data.mako',
- sample=sample, dataset_files=sample.dataset_files )
+
--- a/lib/galaxy/web/controllers/forms.py
+++ b/lib/galaxy/web/controllers/forms.py
@@ -474,8 +474,7 @@ class Forms( BaseController ):
return trans.response.send_redirect( web.url_for( controller='forms',
action='new',
status='error',
- message='Error in importing <b>%s</b> file' % csv_file,
- **kwd))
+ message='Error in importing <b>%s</b> file' % csv_file.file))
self.__imported_from_file = True
return fields, list(layouts)
def __validate_form(self, **kwd):
--- a/templates/admin/requests/edit_request.mako
+++ /dev/null
@@ -1,88 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#edit_request" ).submit();
- }
- });
-});
-</script>
-
-<br/>
-<br/>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='show_request', id=trans.security.encode_id(request.id) )}">
- <span>Browse this request</span></a>
- </li>
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list')}">
- <span>Browse requests</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- <div class="toolFormTitle">Edit request "${request.name}" from ${request.user.email}</div>
- %if len(select_request_type.options) == 1:
- There are no request types created for a new request.
- %else:
- <div class="toolFormBody">
- <form name="edit_request" id="edit_request" action="${h.url_for( controller='requests_admin', action='edit', request_id=request.id)}" method="post" >
- <div class="form-row">
- <label>
- Select Request Type:
- </label>
- ${select_request_type.get_html()}
- </div>
-
- %if select_request_type.get_selected() != ('Select one', 'none'):
- %for i, field in enumerate(widgets):
- <div class="form-row">
- <label>${field['label']}</label>
- ${field['widget'].get_html()}
- %if field['label'] == 'Library' and new_library:
- ${new_library.get_html()}
- %endif
- <div class="toolParamHelp" style="clear: both;">
- ${field['helptext']}
- </div>
- <div style="clear: both"></div>
- </div>
- %endfor
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="save_changes_request_button" value="Save changes"/>
- ##<input type="submit" name="edit_samples_button" value="Edit samples"/>
- </div>
- %endif
- </form>
- </div>
-</div>
-%endif
--- a/templates/requests/sample_datasets.mako
+++ /dev/null
@@ -1,7 +0,0 @@
-<%def name="render_sample_datasets( sample )">
- <a href="${h.url_for(controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id))}">${sample.transferred_dataset_files()}/${len(sample.dataset_files)}</a>
-</%def>
-
-
-
-${render_sample_datasets( sample )}
--- /dev/null
+++ b/templates/requests/common/events.mako
@@ -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=cntrller, 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=cntrller, action='list')}">
+ <span>Browse all requests</span></a>
+ </li>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%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>
--- /dev/null
+++ b/templates/requests/common/show_request.mako
@@ -0,0 +1,547 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/requests/common/sample_state.mako" import="render_sample_state" />
+<%namespace file="/requests/common/sample_datasets.mako" import="render_sample_datasets" />
+
+
+
+<script type="text/javascript">
+$( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
+ }
+ }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#show_request" ).submit();
+ }
+ });
+});
+</script>
+
+
+<script type="text/javascript">
+$(document).ready(function(){
+ //hide the all of the element with class msg_body
+ $(".msg_body").hide();
+ //toggle the componenet with class msg_body
+ $(".msg_head").click(function(){
+ $(this).next(".msg_body").slideToggle(450);
+ });
+});
+</script>
+
+<script type="text/javascript">
+ // Looks for changes in sample states using an async request. Keeps
+ // calling itself (via setTimeout) until all samples are in a terminal
+ // state.
+ var updater = function ( sample_states ) {
+ // Check if there are any items left to track
+ var empty = true;
+ for ( i in sample_states ) {
+ empty = false;
+ break;
+ }
+ if ( ! empty ) {
+ setTimeout( function() { updater_callback( sample_states ) }, 1000 );
+ }
+ };
+ var updater_callback = function ( sample_states ) {
+ // Build request data
+ var ids = []
+ var states = []
+ $.each( sample_states, function ( id, state ) {
+ ids.push( id );
+ states.push( state );
+ });
+ // Make ajax call
+ $.ajax( {
+ type: "POST",
+ url: "${h.url_for( controller='requests_common', action='sample_state_updates' )}",
+ dataType: "json",
+ data: { ids: ids.join( "," ), states: states.join( "," ) },
+ success : function ( data ) {
+ $.each( data, function( id, val, cntrller ) {
+ // Replace HTML
+ var cell1 = $("#sampleState-" + id);
+ cell1.html( val.html_state );
+ var cell2 = $("#sampleDatasets-" + id);
+ cell2.html( val.html_datasets );
+ sample_states[ parseInt(id) ] = val.state;
+ });
+ updater( sample_states );
+ },
+ error: function() {
+ // Just retry, like the old method, should try to be smarter
+ updater( sample_states );
+ }
+ });
+ };
+</script>
+
+<style type="text/css">
+.msg_head {
+ padding: 0px 0px;
+ cursor: pointer;
+}
+</style>
+
+<script type="text/javascript">
+ function stopRKey(evt) {
+ var evt = (evt) ? evt : ((event) ? event : null);
+ var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
+ if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
+ }
+ document.onkeypress = stopRKey
+</script>
+
+%if request.submitted():
+ <% samples_not_ready = request.sequence_run_ready() %>
+ %if samples_not_ready:
+ ${render_msg( "Select a target library and folder for all the samples before starting the sequence run", "warning" )}
+ %endif
+%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=cntrller, action='list', operation='Submit', id=trans.security.encode_id(request.id) )}">
+ <span>Submit request</span></a>
+ </li>
+ %endif
+ %if cntrller == 'requests_admin' and trans.user_is_admin():
+ %if request.submitted():
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, action='list', operation='reject', id=trans.security.encode_id(request.id))}">
+ <span>Reject request</span></a>
+ </li>
+ %endif
+ %endif
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, 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=cntrller, action='list')}">
+ <span>Browse requests</span></a>
+ </li>
+
+</ul>
+
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+
+
+
+<div class="toolForm">
+ <div class="form-row">
+ <div class="msg_list">
+ <h4 class="msg_head"><u>Request Information</u></h4>
+ <div class="msg_body">
+ %for index, rd in enumerate(request_details):
+ <div class="form-row">
+ <label>${rd['label']}</label>
+ %if not rd['value']:
+ <i>None</i>
+ %else:
+ %if rd['label'] == 'State':
+ <a href="${h.url_for( controller=cntrller, action='list', operation='events', id=trans.security.encode_id(request.id) )}">${rd['value']}</a>
+ %else:
+ ${rd['value']}
+ %endif
+ %endif
+ </div>
+ <div style="clear: both"></div>
+ %endfor
+ <div class="form-row">
+ <ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='list', operation='Edit', id=trans.security.encode_id(request.id))}">
+ <span>Edit request details</span></a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<br/>
+
+<div class="toolForm">
+ <form id="show_request" name="show_request" action="${h.url_for( controller='requests_common', cntrller=cntrller, action='request_page', edit_mode=edit_mode )}" method="post" >
+ <div class="form-row">
+ %if current_samples:
+ ## first render the basic info grid
+ ${render_basic_info_grid()}
+ ## then render the other grid(s)
+ <% trans.sa_session.refresh( request.type.sample_form ) %>
+ %for grid_index, grid_name in enumerate(request.type.sample_form.layout):
+ ${render_grid( grid_index, grid_name, request.type.sample_form.fields_of_grid( grid_index ) )}
+ <br/>
+ %endfor
+ %else:
+ <label>There are no samples.</label>
+ %endif
+ </div>
+ %if request.samples and request.submitted():
+ <script type="text/javascript">
+ // Updater
+ updater({${ ",".join( [ '"%s" : "%s"' % ( s.id, s.current_state().name ) for s in request.samples ] ) }});
+ </script>
+ %endif
+
+ %if edit_mode == 'False':
+ <table class="grid">
+ <tbody>
+ <tr>
+ <div class="form-row">
+
+ %if request.unsubmitted():
+ <td>
+ %if current_samples:
+ <label>Copy </label>
+ <input type="integer" name="num_sample_to_copy" value="1" size="3"/>
+ <label>sample(s) from sample</label>
+ ${sample_copy.get_html()}
+ %endif
+ <input type="submit" name="add_sample_button" value="Add New"/>
+ </td>
+ %endif
+ <td>
+ %if len(current_samples) and len(current_samples) <= len(request.samples):
+ <input type="submit" name="edit_samples_button" value="Edit samples"/>
+ %endif
+ </td>
+ </div>
+ </tr>
+ </tbody>
+ </table>
+ %endif
+ %if request.samples or current_samples:
+ <div class="form-row">
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="hidden" name="refresh" value="true" size="40"/>
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ %if edit_mode == 'True':
+ <div class="form-row">
+ <input type="submit" name="save_samples_button" value="Save"/>
+ <input type="submit" name="cancel_changes_button" value="Cancel"/>
+ </div>
+ %elif request.unsubmitted():
+ <div class="form-row">
+ <input type="submit" name="save_samples_button" value="Save"/>
+ </div>
+ %endif
+
+ %endif
+ <input type="hidden" name="id" value="${trans.security.encode_id(request.id)}" />
+ </form>
+</div>
+
+<br/>
+
+%if request.unsubmitted():
+<div class="toolForm">
+ <form id="import" name="import" action="${h.url_for( controller='requests_common', action='request_page', edit_mode=edit_mode, request_id=trans.security.encode_id(request.id) )}" enctype="multipart/form-data" method="post" >
+ <div class="form-row">
+ <div class="msg_list">
+ <h4 class="msg_head"><u>Import samples from csv file</u></h4>
+ <div class="msg_body">
+ <input type="file" name="file_data" />
+ <input type="submit" name="import_samples_button" value="Import samples"/>
+ <br/>
+ <div class="toolParamHelp" style="clear: both;">
+ The csv file must be in the following format:<br/>
+ SampleName,DataLibrary,DataLibraryFolder,FieldValue1,FieldValue2...
+ </div>
+ </div>
+ </div>
+ </div>
+## <input type="hidden" name="request_id" value="${request.id}" />
+ </form>
+</div>
+%endif
+
+<%def name="render_grid( grid_index, grid_name, fields_dict )">
+ <br/>
+ <div class="msg_list">
+ %if grid_name:
+ <h4 class="msg_head"><u>${grid_name}</u></h4>
+ %else:
+ <h4>Grid ${grid_index}</h4>
+ %endif
+ %if edit_mode == 'False' or len(current_samples) <= len(request.samples):
+ <div class="msg_body">
+ %else:
+ <div class="msg_body2">
+ %endif
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ %for index, field in fields_dict.items():
+ <th>
+ ${field['label']}
+ <div class="toolParamHelp" style="clear: both;">
+ <i>${field['helptext']}</i>
+ </div>
+ </th>
+ %endfor
+ <th></th>
+ </tr>
+ <thead>
+ <tbody>
+ <%
+ trans.sa_session.refresh( request )
+ %>
+ %for sample_index, sample in enumerate(current_samples):
+ %if edit_mode == 'True':
+ <tr>
+ ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
+ </tr>
+ %else:
+ <tr>
+ %if sample_index in range(len(request.samples)):
+ ${render_sample( sample_index, sample['name'], sample['field_values'], fields_dict )}
+ %else:
+ ${render_sample_form( sample_index, sample['name'], sample['field_values'], fields_dict)}
+ %endif
+ </tr>
+ %endif
+ %endfor
+ </tbody>
+ </table>
+ </div>
+ </div>
+</%def>
+
+## This function displays the "Basic Information" grid
+<%def name="render_basic_info_grid()">
+ <h4>Sample Information</h4>
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Barcode</th>
+ <th>State</th>
+ <th>Data Library</th>
+ <th>Folder</th>
+ %if request.submitted() or request.complete():
+ <th>Dataset(s) Transferred</th>
+ %endif
+ <th></th>
+ </tr>
+ <thead>
+ <tbody>
+ <%
+ trans.sa_session.refresh( request )
+ %>
+ %for sample_index, info in enumerate(current_samples):
+ <%
+ if sample_index in range(len(request.samples)):
+ sample = request.samples[sample_index]
+ else:
+ sample = None
+ %>
+ %if edit_mode == 'True':
+ <tr>
+ ${show_basic_info_form( sample_index, sample, info )}
+ </tr>
+ %else:
+ <tr>
+ %if sample_index in range(len(request.samples)):
+ <td>${info['name']}</td>
+ <td>${info['barcode']}</td>
+ %if sample.request.unsubmitted():
+ <td>Unsubmitted</td>
+ %else:
+ <td id="sampleState-${sample.id}">${render_sample_state( cntrller, sample )}</td>
+ %endif
+ %if info['library']:
+ <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( info['library'].id ) )}">${info['library'].name}</a></td>
+ %else:
+ <td></td>
+ %endif
+ %if info['folder']:
+ <td>${info['folder'].name}</td>
+ %else:
+ <td></td>
+ %endif
+ %if request.submitted() or request.complete():
+ <td id="sampleDatasets-${sample.id}">
+ ${render_sample_datasets( cntrller, sample )}
+ </td>
+ %endif
+
+
+ %else:
+ ${show_basic_info_form( sample_index, sample, info )}
+ %endif
+ %if request.unsubmitted() or request.rejected():
+ <td>
+ %if sample:
+ %if sample.request.unsubmitted():
+ <a class="action-button" href="${h.url_for( controller='requests_common', cntrller=cntrller, action='delete_sample', request_id=request.id, sample_id=sample_index )}">
+ <img src="${h.url_for('/static/images/delete_icon.png')}" />
+ <span></span></a>
+ %endif
+ %endif
+ </td>
+ %endif
+ </tr>
+ %endif
+ %endfor
+ </tbody>
+ </table>
+</%def>
+
+<%def name="show_basic_info_form( sample_index, sample, info )">
+ <td>
+ <input type="text" name=sample_${sample_index}_name value="${info['name']}" size="10"/>
+ <div class="toolParamHelp" style="clear: both;">
+ <i>${' (required)' }</i>
+ </div>
+ </td>
+ %if cntrller == 'requests':
+ %if sample:
+ %if sample.request.unsubmitted():
+ <td></td>
+ %else:
+ <td><input type="text" name=sample_${sample_index}_barcode value="${info['barcode']}" size="10"/></td>
+ %endif
+ %else:
+ <td></td>
+ %endif
+ %elif cntrller == 'requests_admin':
+ %if sample:
+ %if sample.request.unsubmitted():
+ <td></td>
+ %else:
+ <td><input type="text" name=sample_${sample_index}_barcode value="${info['barcode']}" size="10"/></td>
+ %endif
+ %else:
+ <td></td>
+ %endif
+ %endif
+ %if sample:
+ %if sample.request.unsubmitted():
+ <td>Unsubmitted</td>
+ %else:
+ <td><a href="${h.url_for( controller='requests_admin', action='sample_events', sample_id=sample.id)}">${sample.current_state().name}</a></td>
+ %endif
+ %else:
+ <td></td>
+ %endif
+ <td>${info['lib_widget'].get_html()}</td>
+ <td>${info['folder_widget'].get_html()}</td>
+ %if request.submitted() or request.complete():
+ %if sample:
+ <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">${len(sample.dataset_files)}</a></td>
+ %else:
+ <td><a href="${h.url_for( controller='requests_admin', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">Add</a></td>
+ %endif
+ %endif
+</%def>
+
+<%def name="render_sample( index, sample_name, sample_values, fields_dict )">
+ <td>
+ ${sample_name}
+ </td>
+ %for field_index, field in fields_dict.items():
+ <td>
+ %if sample_values[field_index]:
+ %if field['type'] == 'WorkflowField':
+ %if str(sample_values[field_index]) != 'none':
+ <% workflow = trans.sa_session.query( trans.app.model.StoredWorkflow ).get( int(sample_values[field_index]) ) %>
+ <a href="${h.url_for( controller='workflow', action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name}</a>
+ %endif
+ %else:
+ ${sample_values[field_index]}
+ %endif
+ %else:
+ <i>None</i>
+ %endif
+ </td>
+ %endfor
+</%def>
+
+<%def name="render_sample_form( index, sample_name, sample_values, fields_dict )">
+ <td>
+ ${sample_name}
+ </td>
+ %for field_index, field in fields_dict.items():
+ <td>
+ %if field['type'] == 'TextField':
+ <input type="text" name="sample_${index}_field_${field_index}" value="${sample_values[field_index]}" size="7"/>
+ %elif field['type'] == 'SelectField':
+ <select name="sample_${index}_field_${field_index}" last_selected_value="2">
+ %for option_index, option in enumerate(field['selectlist']):
+ %if option == sample_values[field_index]:
+ <option value="${option}" selected>${option}</option>
+ %else:
+ <option value="${option}">${option}</option>
+ %endif
+ %endfor
+ </select>
+ %elif field['type'] == 'WorkflowField':
+ <select name="sample_${index}_field_${field_index}">
+ %if str(sample_values[field_index]) == 'none':
+ <option value="none" selected>Select one</option>
+ %else:
+ <option value="none">Select one</option>
+ %endif
+ %for option_index, option in enumerate(request.user.stored_workflows):
+ %if not option.deleted:
+ %if str(option.id) == str(sample_values[field_index]):
+ <option value="${option.id}" selected>${option.name}</option>
+ %else:
+ <option value="${option.id}">${option.name}</option>
+ %endif
+ %endif
+ %endfor
+ </select>
+ %elif field['type'] == 'CheckboxField':
+ <input type="checkbox" name="sample_${index}_field_${field_index}" value="Yes"/>
+ %endif
+ <div class="toolParamHelp" style="clear: both;">
+ <i>${'('+field['required']+')' }</i>
+ </div>
+ </td>
+ %endfor
+</%def>
+
+
+
+
+
+
+
+
+
+
--- a/templates/admin/requests/new_request.mako
+++ /dev/null
@@ -1,94 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
- }
- }
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#new_request" ).submit();
- }
- });
-});
-</script>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js("jquery.autocomplete", "autocomplete_tagging" )}
-</%def>
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "autocomplete_tagging" )}
-</%def>
-
-<br/>
-<br/>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='list')}">
- <span>Browse requests</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- <div class="toolFormTitle">Add a new request</div>
- %if len(select_request_type.options) == 1:
- There are no request types created for a new request.
- %else:
- <div class="toolFormBody">
- <form name="new_request" id="new_request" action="${h.url_for( controller='requests_admin', action='new', create=True )}" method="post" >
- <div class="form-row">
- <label>
- Select Request Type
- </label>
- ${select_request_type.get_html()}
- </div>
-
- %if select_request_type.get_selected() != ('Select one', 'none'):
- %for i, field in enumerate(widgets):
- <div class="form-row">
- <label>${field['label']}</label>
- ${field['widget'].get_html()}
- %if field['label'] == 'Library' and new_library:
- ${new_library.get_html()}
- %endif
- <div class="toolParamHelp" style="clear: both;">
- ${field['helptext']}
- </div>
- <div style="clear: both"></div>
- </div>
- %endfor
- <div class="form-row">
- <div style="float: left; width: 250px; margin-right: 10px;">
- <input type="hidden" name="refresh" value="true" size="40"/>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="form-row">
- <input type="submit" name="create_request_button" value="Save"/>
- <input type="submit" name="create_request_samples_button" value="Add samples"/>
- </div>
- %endif
- </form>
- </div>
-</div>
-%endif
--- a/templates/sample/sample_events.mako
+++ /dev/null
@@ -1,45 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<%def name="title()">Events for Sample ${sample_name}</%def>
-
-
-<h2>Events for Sample "${sample_name}"</h2>
-
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( controller='requests', 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 requests</span></a>
- </li>
-</ul>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<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>
--- /dev/null
+++ b/templates/requests/common/sample_datasets.mako
@@ -0,0 +1,7 @@
+<%def name="render_sample_datasets( cntrller, sample )">
+ <a href="${h.url_for(controller='requests_common', cntrller=cntrller, action='show_datatx_page', sample_id=trans.security.encode_id(sample.id))}">${sample.transferred_dataset_files()}/${len(sample.dataset_files)}</a>
+</%def>
+
+
+
+${render_sample_datasets( cntrller, sample )}
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1485,14 +1485,13 @@ class TwillTestCase( unittest.TestCase )
url ="%s&%s=%s" % ( url, key, role_ids_str )
self.home()
self.visit_url( "%s/%s" % ( self.url, url ) )
- print url
check_str = "Permissions updated for request type '%s'" % request_type_name
self.check_page_for_string( check_str )
self.home()
def create_request( self, request_type_id, name, desc, fields ):
self.home()
- self.visit_url( "%s/requests/new?create=True&select_request_type=%i" % ( self.url,
- request_type_id ) )
+ self.visit_url( "%s/requests_common/new?select_request_type=%i&refresh=true&cntrller=requests" % ( self.url,
+ request_type_id ) )
self.check_page_for_string( 'Add a new request' )
tc.fv( "1", "name", name )
tc.fv( "1", "desc", desc )
@@ -1514,21 +1513,20 @@ class TwillTestCase( unittest.TestCase )
self.check_page_for_string( new_desc )
def add_samples( self, request_id, request_name, samples ):
self.home()
- url = "%s/requests/list?sort=-create_time&operation=show_request&id=%s" % ( self.url, self.security.encode_id( request_id ) )
+ url = "%s/requests/list?operation=show&id=%s" % ( self.url, self.security.encode_id( request_id ) )
self.visit_url( url )
self.check_page_for_string( 'Sequencing Request "%s"' % request_name )
self.check_page_for_string( 'There are no samples.' )
# this redundant stmt below is add so that the second form in
# the page gets selected
- tc.fv( "3", "request_id", request_id )
+ url = ["%s/requests_common/request_page?cntrller=requests&edit_mode=False&id=%s" % ( self.url, self.security.encode_id( request_id ) )]
for sample_index, sample in enumerate(samples):
- tc.submit( "add_sample_button" )
- self.check_page_for_string( 'Sequencing Request "%s"' % request_name )
sample_name, fields = sample
- tc.fv( "3", "sample_%i_name" % sample_index, sample_name )
+ url.append("sample_%i_name=%s" % (sample_index, sample_name.replace(' ', '+')))
for field_index, field_value in enumerate(fields):
- tc.fv( "3", "sample_%i_field_%i" % ( sample_index, field_index ), field_value )
- tc.submit( "save_samples_button" )
+ url.append("sample_%i_field_%i=%s" % ( sample_index, field_index , field_value.replace(' ', '+') ))
+ url.append("save_samples_button=Save")
+ self.visit_url('&'.join(url))
for sample_name, fields in samples:
self.check_page_for_string( sample_name )
self.check_page_for_string( 'Unsubmitted' )
@@ -1549,19 +1547,24 @@ class TwillTestCase( unittest.TestCase )
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.visit_url( "%s/requests/list?&operation=show&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 ):
+ def add_bar_codes( self, request_id, request_name, bar_codes, samples ):
self.home()
- self.visit_url( "%s/requests_admin/bar_codes?request_id=%i" % (self.url, request_id) )
- self.check_page_for_string( 'Bar codes for Samples of Request "%s"' % request_name )
+ url = "%s/requests/list?operation=show&id=%s" % ( self.url, self.security.encode_id( request_id ) )
+ self.visit_url( url )
+ self.check_page_for_string( 'Sequencing Request "%s"' % request_name )
+ url = ["%s/requests_common/request_page?save_samples_button=Save&cntrller=requests&edit_mode=True&id=%s" % ( self.url, self.security.encode_id( request_id ) )]
for index, bar_code in enumerate(bar_codes):
- tc.fv( "1", "sample_%i_bar_code" % index, bar_code )
- tc.submit( "save_bar_codes" )
- self.check_page_for_string( 'Bar codes have been saved for this request' )
+ url.append("sample_%i_barcode=%s" % (index, bar_code ))
+ url.append("sample_%i_name=%s" % (index, samples[index].name.replace(' ', '+') ))
+ self.visit_url('&'.join(url))
+ self.check_page_for_string( 'Changes made to the sample(s) are saved.' )
+ for index, bar_code in enumerate(bar_codes):
+ self.check_page_for_string( bar_code )
def change_sample_state( self, sample_name, sample_id, new_state_id, new_state_name, comment='' ):
self.home()
- self.visit_url( "%s/requests_admin/show_events?sample_id=%i" % (self.url, sample_id) )
+ self.visit_url( "%s/requests_common/sample_events?cntrller=requests_admin&sample_id=%i" % (self.url, sample_id) )
self.check_page_for_string( 'Events for Sample "%s"' % sample_name )
tc.fv( "1", "select_state", str(new_state_id) )
tc.fv( "1", "comment", comment )
--- a/templates/requests/show_data.mako
+++ /dev/null
@@ -1,86 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<script type="text/javascript">
-$(document).ready(function(){
- //hide the all of the element with class msg_body
- $(".msg_body").hide();
- //toggle the componenet with class msg_body
- $(".msg_head").click(function(){
- $(this).next(".msg_body").slideToggle(450);
- });
-});
-</script>
-<style type="text/css">
-.msg_head {
- padding: 0px 0px;
- cursor: pointer;
-}
-
-}
-</style>
-
-
-<h2>Data transfer from Sequencer</h2>
-<h3>Sample "${sample.name}" of Request "${sample.request.name}"</h3>
-
-<ul class="manage-table-actions">
- %if sample.request.submitted() and sample.inprogress_dataset_files():
- <li>
- <a class="action-button" href="${h.url_for( controller='requests', action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">
- <span>Refresh this page</span></a>
- </li>
- %endif
- %if sample.library:
- <li>
- <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">
- <span>${sample.library.name} Data Library</span></a>
- </li>
- %endif
- <li>
- <a class="action-button" href="${h.url_for( controller='requests', action='list', operation='show_request', id=trans.security.encode_id(sample.request.id) )}">
- <span>Browse this request</span></a>
- </li>
-</ul>
-
-<div class="toolForm">
- <form name="get_data" action="${h.url_for( controller='requests_admin', action='get_data', sample_id=sample.id)}" method="post" >
- <div class="form-row">
- %if len(dataset_files):
- <table class="grid">
- <thead>
- <tr>
- <th>Dataset File</th>
- <th>Transfer Status</th>
- </tr>
- <thead>
- <tbody>
- %for dataset_index, dataset_file in enumerate(dataset_files):
- ${sample_dataset_files( dataset_index, dataset_file[0], dataset_file[1] )}
- %endfor
- </tbody>
- </table>
- %else:
- There are no dataset files.
- %endif
- </div>
- </form>
-</div>
-
-<%def name="sample_dataset_files( dataset_index, dataset_file, status )">
- <tr>
- <td>${dataset_file.split('/')[-1]}</td>
- <td>
- %if status == sample.transfer_status.IN_PROGRESS:
- <i>${status}</i>
- %else:
- ${status}
- %endif
- </td>
- </tr>
-</%def>
--- /dev/null
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -0,0 +1,1099 @@
+from galaxy.web.base.controller import *
+from galaxy.web.framework.helpers import time_ago, iff, grids
+from galaxy.model.orm import *
+from galaxy.datatypes import sniff
+from galaxy import model, util
+from galaxy.util.streamball import StreamBall
+import logging, tempfile, zipfile, tarfile, os, sys, subprocess
+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
+import pexpect
+import ConfigParser, threading, time
+from amqplib import client_0_8 as amqp
+import csv
+log = logging.getLogger( __name__ )
+
+
+class RequestsCommon( BaseController ):
+
+ @web.json
+ def sample_state_updates( self, trans, ids=None, states=None, cntrller=None ):
+ # Avoid caching
+ trans.response.headers['Pragma'] = 'no-cache'
+ trans.response.headers['Expires'] = '0'
+ # Create new HTML for any that have changed
+ rval = {}
+ if ids is not None and states is not None:
+ ids = map( int, ids.split( "," ) )
+ states = states.split( "," )
+ for id, state in zip( ids, states ):
+ sample = trans.sa_session.query( self.app.model.Sample ).get( id )
+ if sample.current_state().name != state:
+ rval[id] = {
+ "state": sample.current_state().name,
+ "datasets": len(sample.dataset_files),
+ "html_state": unicode( trans.fill_template( "requests/common/sample_state.mako", sample=sample, cntrller=cntrller ), 'utf-8' ),
+ "html_datasets": unicode( trans.fill_template( "requests/common/sample_datasets.mako", trans=trans, sample=sample, cntrller=cntrller ), 'utf-8' )
+ }
+ return rval
+
+
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def new(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ if params.get('select_request_type', False) == 'True':
+ return trans.fill_template( '/requests/common/new_request.mako',
+ cntrller=cntrller,
+ select_request_type=self.__select_request_type(trans, 'none'),
+ widgets=[],
+ message=message,
+ status=status)
+ elif params.get('create_request_button', False) == 'Save' \
+ or params.get('create_request_samples_button', False) == 'Add 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', '')) \
+ or util.restore_text(params.get('select_user', '')) == unicode('none'):
+ message = 'Please enter the <b>Name</b> of the request and the <b>user</b> on behalf of whom this request will be submitted before saving this request'
+ kwd['create'] = 'True'
+ kwd['status'] = 'error'
+ kwd['message'] = message
+ kwd['create_request_button'] = None
+ kwd['create_request_samples_button'] = None
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller=cntrller,
+ action='new',
+ **kwd) )
+ request = self.__save_request(trans, None, **kwd)
+ message = 'The new request named <b>%s</b> has been created' % request.name
+ if params.get('create_request_button', False) == 'Save':
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ message=message ,
+ status='done') )
+ elif params.get('create_request_samples_button', False) == 'Add samples':
+ new_kwd = {}
+ new_kwd['id'] = trans.security.encode_id(request.id)
+ new_kwd['operation'] = 'show'
+ new_kwd['add_sample'] = True
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ message=message ,
+ status='done',
+ **new_kwd) )
+ elif params.get('refresh', False) == 'true':
+ return self.__show_request_form(trans, **kwd)
+
+ def __select_request_type(self, trans, rtid):
+ requesttype_list = trans.user.accessible_request_types(trans)
+ rt_ids = ['none']
+ for rt in requesttype_list:
+ if not rt.deleted:
+ rt_ids.append(str(rt.id))
+ select_reqtype = SelectField('select_request_type',
+ refresh_on_change=True,
+ refresh_on_change_values=rt_ids[1:])
+ if rtid == 'none':
+ select_reqtype.add_option('Select one', 'none', selected=True)
+ else:
+ select_reqtype.add_option('Select one', 'none')
+ for rt in requesttype_list:
+ if not rt.deleted:
+ if rtid == rt.id:
+ select_reqtype.add_option(rt.name, rt.id, selected=True)
+ else:
+ select_reqtype.add_option(rt.name, rt.id)
+ return select_reqtype
+
+ def __show_request_form(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ try:
+ request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
+ except:
+ return trans.fill_template( '/requests/common/new_request.mako',
+ cntrller=cntrller,
+ select_request_type=self.__select_request_type(trans, 'none'),
+ widgets=[],
+ message=message,
+ status=status)
+ form_values = None
+ select_request_type = self.__select_request_type(trans, request_type.id)
+ # user
+ if cntrller == 'requests_admin' and trans.user_is_admin():
+ user_id = params.get( 'select_user', 'none' )
+ try:
+ user = trans.sa_session.query( trans.app.model.User ).get( int( user_id ) )
+ except:
+ user = None
+ elif cntrller == 'requests':
+ user = trans.user
+ # list of widgets to be rendered on the request form
+ widgets = []
+ if cntrller == 'requests_admin' and trans.user_is_admin():
+ widgets.append(dict(label='Select user',
+ widget=self.__select_user(trans, user_id),
+ helptext='The request would be submitted on behalf of this user (Required)'))
+ widgets.append(dict(label='Name of the Experiment',
+ widget=TextField('name', 40,
+ util.restore_text( params.get( 'name', '' ) )),
+ helptext='(Required)'))
+ widgets.append(dict(label='Description',
+ widget=TextField('desc', 40,
+ util.restore_text( params.get( 'desc', '' ) )),
+ helptext='(Optional)'))
+ widgets = widgets + request_type.request_form.get_widgets( user, **kwd )
+ widgets.append(dict(label='Send email notification when the sequencing request is complete',
+ widget=CheckboxField('email_notify', False),
+ helptext='Email would be sent to the lab admin and the user for whom this request has been created.'))
+ return trans.fill_template( '/requests/common/new_request.mako',
+ cntrller=cntrller,
+ select_request_type=select_request_type,
+ request_type=request_type,
+ widgets=widgets,
+ message=message,
+ status=status)
+ def __select_user(self, trans, userid):
+ user_list = trans.sa_session.query( trans.app.model.User )\
+ .order_by( trans.app.model.User.email.asc() )
+ user_ids = ['none']
+ for user in user_list:
+ if not user.deleted:
+ user_ids.append(str(user.id))
+ select_user = SelectField('select_user',
+ refresh_on_change=True,
+ refresh_on_change_values=user_ids[1:])
+ if userid == 'none':
+ select_user.add_option('Select one', 'none', selected=True)
+ else:
+ select_user.add_option('Select one', 'none')
+ for user in user_list:
+ if not user.deleted:
+ if userid == str(user.id):
+ select_user.add_option(user.email, user.id, selected=True)
+ else:
+ select_user.add_option(user.email, user.id)
+ return select_user
+ def __save_request(self, trans, request, **kwd):
+ '''
+ This method saves a new request if request_id is None.
+ '''
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
+ if request:
+ user = request.user
+ else:
+ if cntrller == 'requests_admin' and trans.user_is_admin():
+ user = trans.sa_session.query( trans.app.model.User ).get( int( params.get( 'select_user', '' ) ) )
+ elif cntrller == 'requests':
+ user = trans.user
+ name = util.restore_text(params.get('name', ''))
+ desc = util.restore_text(params.get('desc', ''))
+ notify = CheckboxField.is_checked( params.get('email_notify', '') )
+ # fields
+ values = []
+ for index, field in enumerate(request_type.request_form.fields):
+ if field['type'] == 'AddressField':
+ value = util.restore_text(params.get('field_%i' % index, ''))
+ if value == 'new':
+ # save this new address in the list of this user's addresses
+ user_address = trans.app.model.UserAddress( user=user )
+ user_address.desc = util.restore_text(params.get('field_%i_short_desc' % index, ''))
+ user_address.name = util.restore_text(params.get('field_%i_name' % index, ''))
+ user_address.institution = util.restore_text(params.get('field_%i_institution' % index, ''))
+ user_address.address = util.restore_text(params.get('field_%i_address1' % index, ''))+' '+util.restore_text(params.get('field_%i_address2' % index, ''))
+ user_address.city = util.restore_text(params.get('field_%i_city' % index, ''))
+ user_address.state = util.restore_text(params.get('field_%i_state' % index, ''))
+ user_address.postal_code = util.restore_text(params.get('field_%i_postal_code' % index, ''))
+ user_address.country = util.restore_text(params.get('field_%i_country' % index, ''))
+ user_address.phone = util.restore_text(params.get('field_%i_phone' % index, ''))
+ trans.sa_session.add( user_address )
+ trans.sa_session.flush()
+ trans.sa_session.refresh( user )
+ values.append(int(user_address.id))
+ elif value == unicode('none'):
+ values.append('')
+ else:
+ values.append(int(value))
+ elif field['type'] == 'CheckboxField':
+ values.append(CheckboxField.is_checked( params.get('field_%i' % index, '') ))
+ else:
+ values.append(util.restore_text(params.get('field_%i' % index, '')))
+ form_values = trans.app.model.FormValues(request_type.request_form, values)
+ trans.sa_session.add( form_values )
+ trans.sa_session.flush()
+ if not request:
+ request = trans.app.model.Request(name, desc, request_type,
+ user, form_values, notify)
+ 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
+ request.type = request_type
+ request.user = user
+ request.notify = notify
+ request.values = form_values
+ trans.sa_session.add( request )
+ trans.sa_session.flush()
+ return request
+
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def edit(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id( params.get( 'id', None ) ) )
+ except:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message="Invalid request ID") )
+ if params.get('show', False) == 'True':
+ return self.__edit_request(trans, **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', '')):
+ message = 'Please enter the <b>Name</b> of the request'
+ kwd['status'] = 'error'
+ kwd['message'] = message
+ kwd['show'] = 'True'
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller=cntrller,
+ action='edit',
+ **kwd) )
+ request = self.__save_request(trans, request, **kwd)
+ message = '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=cntrller,
+ cntrller=cntrller,
+ action='list',
+ message=message ,
+ status='done') )
+ elif params.get('edit_samples_button', False) == 'Edit samples':
+ new_kwd = {}
+ new_kwd['id'] = request.id
+ new_kwd['edit_samples_button'] = 'Edit samples'
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ cntrller=cntrller,
+ action='show',
+ message=message ,
+ status='done',
+ **new_kwd) )
+ elif params.get('refresh', False) == 'true':
+ return self.__edit_request(trans, **kwd)
+
+ def __edit_request(self, trans, **kwd):
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
+ except:
+ message = "Invalid request ID"
+ log.warn( message )
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ cntrller=cntrller,
+ action='list',
+ status='error',
+ message=message) )
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ select_request_type = self.__select_request_type(trans, request.type.id)
+ # list of widgets to be rendered on the request form
+ widgets = []
+ if util.restore_text( params.get( 'name', '' ) ):
+ name = util.restore_text( params.get( 'name', '' ) )
+ else:
+ name = request.name
+ widgets.append(dict(label='Name',
+ widget=TextField('name', 40, name),
+ helptext='(Required)'))
+ if util.restore_text( params.get( 'desc', '' ) ):
+ desc = util.restore_text( params.get( 'desc', '' ) )
+ else:
+ desc = request.desc
+ widgets.append(dict(label='Description',
+ widget=TextField('desc', 40, desc),
+ helptext='(Optional)'))
+ widgets = widgets + request.type.request_form.get_widgets( request.user, request.values.content, **kwd )
+ widgets.append(dict(label='Send email notification once the sequencing request is complete',
+ widget=CheckboxField('email_notify', request.notify),
+ helptext=''))
+ return trans.fill_template( 'requests/common/edit_request.mako',
+ cntrller=cntrller,
+ select_request_type=select_request_type,
+ request_type=request.type,
+ request=request,
+ widgets=widgets,
+ message=message,
+ status=status)
+ def __validate(self, trans, cntrller, request):
+ '''
+ Validates the request entered by the user
+ '''
+ if not request.samples:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ message='Please add one or more samples to this request before submitting.',
+ status='error',
+ id=trans.security.encode_id(request.id)) )
+ empty_fields = []
+ # check rest of the fields of the form
+ for index, field in enumerate(request.type.request_form.fields):
+ if field['required'] == 'required' and request.values.content[index] in ['', None]:
+ empty_fields.append(field['label'])
+ if empty_fields:
+ message = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name
+ for ef in empty_fields:
+ message = message + '<b>' +ef + '</b><br/>'
+ return message
+ return None
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def submit(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
+ except:
+ message = "Invalid request ID"
+ log.warn( message )
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message=message,
+ **kwd) )
+ message = self.__validate(trans, cntrller, request)
+ if message:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='edit',
+ status = 'error',
+ message=message,
+ id=trans.security.encode_id(request.id) ) )
+ # change the request state to 'Submitted'
+ if request.user.email is not trans.user:
+ comments = "Request submitted 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 created.')
+ trans.sa_session.add( event )
+ trans.sa_session.add( request )
+ trans.sa_session.flush()
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ id=trans.security.encode_id(request.id),
+ status='done',
+ message='The request <b>%s</b> has been submitted.' % request.name
+ ) )
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def delete(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ id_list = util.listify( kwd['id'] )
+ for id in id_list:
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
+ except:
+ message = "Invalid request ID"
+ log.warn( message )
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message=message,
+ **kwd) )
+ request.deleted = True
+ trans.sa_session.add( request )
+ # delete all the samples belonging to this request
+ for s in request.samples:
+ s.deleted = True
+ trans.sa_session.add( s )
+ trans.sa_session.flush()
+ message = '%i request(s) has been deleted.' % len(id_list)
+ status = 'done'
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status=status,
+ message=message) )
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def undelete(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ id_list = util.listify( kwd['id'] )
+ for id in id_list:
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
+ except:
+ message = "Invalid request ID"
+ log.warn( message )
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message=message,
+ **kwd) )
+ request.deleted = False
+ trans.sa_session.add( request )
+ # undelete all the samples belonging to this request
+ for s in request.samples:
+ s.deleted = False
+ trans.sa_session.add( s )
+ trans.sa_session.flush()
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='done',
+ message='%i request(s) has been undeleted.' % len(id_list) ) )
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def events(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
+ except:
+ message = "Invalid request ID"
+ log.warn( message )
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message=message) )
+ events_list = []
+ all_events = request.events
+ for event in all_events:
+ events_list.append((event.state, time_ago(event.update_time), event.comment))
+ return trans.fill_template( '/requests/common/events.mako',
+ cntrller=cntrller,
+ events_list=events_list, request=request)
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def show(self, trans, **kwd):
+ params = util.Params( kwd )
+ message = util.restore_text( params.get( 'message', '' ) )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ status = params.get( 'status', 'done' )
+ add_sample = params.get('add_sample', False)
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
+ except:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message="Invalid request ID") )
+ # get all data libraries accessible to this user
+ libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
+ current_samples = []
+ for i, s in enumerate(request.samples):
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
+ current_samples.append(dict(name=s.name,
+ barcode=s.bar_code,
+ library=s.library,
+ folder=s.folder,
+ dataset_files=s.dataset_files,
+ field_values=s.values.content,
+ lib_widget=lib_widget,
+ folder_widget=folder_widget))
+ if add_sample:
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user,
+ len(current_samples)+1,
+ libraries, None, **kwd)
+ current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
+ barcode='',
+ library=None,
+ folder=None,
+ dataset_files=[],
+ field_values=['' for field in request.type.sample_form.fields],
+ lib_widget=lib_widget,
+ folder_widget=folder_widget))
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples=current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details='hide', edit_mode=util.restore_text( params.get( 'edit_mode', 'False' ) ),
+ message=message, status=status )
+
+ def __update_samples(self, trans, request, **kwd):
+ '''
+ This method retrieves all the user entered sample information and
+ returns an list of all the samples and their field values
+ '''
+ params = util.Params( kwd )
+ details = params.get( 'details', 'hide' )
+ edit_mode = params.get( 'edit_mode', 'False' )
+ # get all data libraries accessible to this user
+ libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
+
+ current_samples = []
+ for i, s in enumerate(request.samples):
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
+ current_samples.append(dict(name=s.name,
+ barcode=s.bar_code,
+ library=s.library,
+ folder=s.folder,
+ field_values=s.values.content,
+ lib_widget=lib_widget,
+ folder_widget=folder_widget))
+ if edit_mode == 'False':
+ sample_index = len(request.samples)
+ else:
+ sample_index = 0
+ while True:
+ lib_id = None
+ folder_id = None
+ if params.get( 'sample_%i_name' % sample_index, '' ):
+ # data library
+ try:
+ library = trans.sa_session.query( trans.app.model.Library ).get( int( params.get( 'sample_%i_library_id' % sample_index, None ) ) )
+ lib_id = library.id
+ except:
+ library = None
+ # folder
+ try:
+ folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( int( params.get( 'sample_%i_folder_id' % sample_index, None ) ) )
+ folder_id = folder.id
+ except:
+ if library:
+ folder = library.root_folder
+ else:
+ folder = None
+ sample_info = dict( name=util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ),
+ barcode=util.restore_text( params.get( 'sample_%i_barcode' % sample_index, '' ) ),
+ library=library,
+ folder=folder)
+ sample_info['field_values'] = []
+ for field_index in range(len(request.type.sample_form.fields)):
+ sample_info['field_values'].append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) ))
+ if edit_mode == 'False':
+ sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans, request.user,
+ sample_index, libraries,
+ None, lib_id, folder_id, **kwd)
+ current_samples.append(sample_info)
+ else:
+ sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans,
+ request.user,
+ sample_index,
+ libraries,
+ request.samples[sample_index],
+ **kwd)
+ current_samples[sample_index] = sample_info
+ sample_index = sample_index + 1
+ else:
+ break
+ return current_samples, details, edit_mode, libraries
+
+ def __library_widgets(self, trans, user, sample_index, libraries, sample=None, lib_id=None, folder_id=None, **kwd):
+ '''
+ This method creates the data library & folder selectbox for creating &
+ editing samples. First we get a list of all the libraries accessible to
+ the current user and display it in a selectbox. If the user has selected an
+ existing library then display all the accessible sub folders of the selected
+ data library.
+ '''
+ params = util.Params( kwd )
+ # data library selectbox
+ if not lib_id:
+ lib_id = params.get( "sample_%i_library_id" % sample_index, 'none' )
+ selected_lib = None
+ if sample and lib_id == 'none':
+ if sample.library:
+ lib_id = str(sample.library.id)
+ selected_lib = sample.library
+ # create data library selectbox with refresh on change enabled
+ lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
+ lib_widget = SelectField( "sample_%i_library_id" % sample_index,
+ refresh_on_change=True,
+ refresh_on_change_values=lib_id_list )
+ # fill up the options in the Library selectbox
+ # first option 'none' is the value for "Select one" option
+ if lib_id == 'none':
+ lib_widget.add_option('Select one', 'none', selected=True)
+ else:
+ lib_widget.add_option('Select one', 'none')
+ # all the libraries available to the selected user
+ for lib, hidden_folder_ids in libraries.items():
+ if str(lib.id) == str(lib_id):
+ lib_widget.add_option(lib.name, lib.id, selected=True)
+ selected_lib, selected_hidden_folder_ids = lib, hidden_folder_ids.split(',')
+ else:
+ lib_widget.add_option(lib.name, lib.id)
+ lib_widget.refresh_on_change_values.append(lib.id)
+ # create the folder selectbox
+ folder_widget = SelectField( "sample_%i_folder_id" % sample_index )
+ # when editing a request, either the user has already selected a subfolder or not
+ if sample:
+ if sample.folder:
+ current_fid = sample.folder.id
+ else:
+ # when a folder not yet associated with the request then the
+ # the current folder is set to the root_folder of the
+ # parent data library if present.
+ if sample.library:
+ current_fid = sample.library.root_folder.id
+ else:
+ current_fid = params.get( "sample_%i_folder_id" % sample_index, 'none' )
+ else:
+ if folder_id:
+ current_fid = folder_id
+ else:
+ current_fid = 'none'
+ # first option
+ if lib_id == 'none':
+ folder_widget.add_option('Select one', 'none', selected=True)
+ else:
+ folder_widget.add_option('Select one', 'none')
+ if selected_lib:
+ # get all show-able folders for the selected library
+ showable_folders = trans.app.security_agent.get_showable_folders( user, user.all_roles(),
+ selected_lib,
+ [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ],
+ selected_hidden_folder_ids )
+ for f in showable_folders:
+ if str(f.id) == str(current_fid):
+ folder_widget.add_option(f.name, f.id, selected=True)
+ else:
+ folder_widget.add_option(f.name, f.id)
+ return lib_widget, folder_widget
+
+ def __copy_sample(self, current_samples):
+ copy_list = SelectField('copy_sample')
+ copy_list.add_option('None', -1, selected=True)
+ for i, s in enumerate(current_samples):
+ copy_list.add_option(s['name'], i)
+ return copy_list
+
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def request_page(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ try:
+ request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id( kwd['id']) )
+ except:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message="Invalid request ID") )
+ # get the user entered sample details
+ current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd )
+ if params.get('import_samples_button', False) == 'Import samples':
+ return self.__import_samples(trans, cntrller, request, current_samples, details, libraries, **kwd)
+ elif params.get('add_sample_button', False) == 'Add New':
+ # add an empty or filled sample
+ # if the user has selected a sample no. to copy then copy the contents
+ # of the src sample to the new sample else an empty sample
+ src_sample_index = int(params.get( 'copy_sample', -1 ))
+ # get the number of new copies of the src sample
+ num_sample_to_copy = int(params.get( 'num_sample_to_copy', 1 ))
+ if src_sample_index == -1:
+ for ns in range(num_sample_to_copy):
+ # empty sample
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user,
+ len(current_samples),
+ libraries, None, **kwd)
+ current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
+ barcode='',
+ library=None,
+ folder=None,
+ field_values=['' for field in request.type.sample_form.fields],
+ lib_widget=lib_widget,
+ folder_widget=folder_widget))
+ else:
+ src_library_id = current_samples[src_sample_index]['lib_widget'].get_selected()[1]
+ src_folder_id = current_samples[src_sample_index]['folder_widget'].get_selected()[1]
+ for ns in range(num_sample_to_copy):
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user,
+ len(current_samples),
+ libraries, sample=None,
+ lib_id=src_library_id,
+ folder_id=src_folder_id,
+ **kwd)
+ current_samples.append(dict(name=current_samples[src_sample_index]['name']+'_%i' % (len(current_samples)+1),
+ barcode='',
+ library_id='none',
+ folder_id='none',
+ field_values=[val for val in current_samples[src_sample_index]['field_values']],
+ lib_widget=lib_widget,
+ folder_widget=folder_widget))
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples=current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details,
+ edit_mode=edit_mode)
+ elif params.get('save_samples_button', False) == 'Save':
+ # check for duplicate sample names
+ message = ''
+ for index in range(len(current_samples)-len(request.samples)):
+ sample_index = index + len(request.samples)
+ sample_name = current_samples[sample_index]['name']
+ if not sample_name.strip():
+ message = 'Please enter the name of sample number %i' % sample_index
+ break
+ count = 0
+ for i in range(len(current_samples)):
+ if sample_name == current_samples[i]['name']:
+ count = count + 1
+ if count > 1:
+ message = "This request has <b>%i</b> samples with the name <b>%s</b>.\nSamples belonging to a request must have unique names." % (count, sample_name)
+ break
+ if message:
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples = current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details, edit_mode=edit_mode,
+ status='error', message=message)
+ # save all the new/unsaved samples entered by the user
+ if edit_mode == 'False':
+ for index in range(len(current_samples)-len(request.samples)):
+ sample_index = len(request.samples)
+ form_values = trans.app.model.FormValues(request.type.sample_form,
+ current_samples[sample_index]['field_values'])
+ trans.sa_session.add( form_values )
+ trans.sa_session.flush()
+ s = trans.app.model.Sample(current_samples[sample_index]['name'], '',
+ request, form_values,
+ current_samples[sample_index]['barcode'],
+ current_samples[sample_index]['library'],
+ current_samples[sample_index]['folder'],
+ dataset_files=[])
+ trans.sa_session.add( s )
+ trans.sa_session.flush()
+
+ else:
+ status = 'done'
+ message = 'Changes made to the sample(s) are saved. '
+ for sample_index in range(len(current_samples)):
+ sample = request.samples[sample_index]
+ sample.name = current_samples[sample_index]['name']
+ sample.library = current_samples[sample_index]['library']
+ sample.folder = current_samples[sample_index]['folder']
+ if request.submitted():
+ bc_message = self.__validate_barcode(trans, sample, current_samples[sample_index]['barcode'])
+ if bc_message:
+ status = 'error'
+ message += bc_message
+ else:
+ if not sample.bar_code:
+ # if this is a 'new' (still in its first state) sample
+ # change the state to the next
+ if sample.current_state().id == request.type.states[0].id:
+ event = trans.app.model.SampleEvent(sample,
+ request.type.states[1],
+ 'Sample added to the system')
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ sample.bar_code = current_samples[sample_index]['barcode']
+ trans.sa_session.add( sample )
+ trans.sa_session.flush()
+ form_values = trans.sa_session.query( trans.app.model.FormValues ).get( sample.values.id )
+ form_values.content = current_samples[sample_index]['field_values']
+ trans.sa_session.add( form_values )
+ trans.sa_session.flush()
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ id=trans.security.encode_id(request.id),
+ status=status,
+ message=message ))
+ elif params.get('edit_samples_button', False) == 'Edit samples':
+ edit_mode = 'True'
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples=current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details, libraries=libraries,
+ edit_mode=edit_mode)
+ elif params.get('cancel_changes_button', False) == 'Cancel':
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ id=trans.security.encode_id(request.id)) )
+ else:
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples=current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details, libraries=libraries,
+ edit_mode=edit_mode, status=status, message=message)
+
+ def __import_samples(self, trans, cntrller, request, current_samples, details, libraries, **kwd):
+ '''
+ This method reads the samples csv file and imports all the samples
+ The format of the csv file is:
+ SampleName,DataLibrary,DataLibraryFolder,Field1,Field2....
+ '''
+ try:
+ params = util.Params( kwd )
+ edit_mode = params.get( 'edit_mode', 'False' )
+ file_obj = params.get('file_data', '')
+ reader = csv.reader(file_obj.file)
+ for row in reader:
+ lib_id = None
+ folder_id = None
+ lib = trans.sa_session.query( trans.app.model.Library ) \
+ .filter( and_( trans.app.model.Library.table.c.name==row[1], \
+ trans.app.model.Library.table.c.deleted==False ) )\
+ .first()
+ if lib:
+ folder = trans.sa_session.query( trans.app.model.LibraryFolder ) \
+ .filter( and_( trans.app.model.LibraryFolder.table.c.name==row[2], \
+ trans.app.model.LibraryFolder.table.c.deleted==False ) )\
+ .first()
+ if folder:
+ lib_id = lib.id
+ folder_id = folder.id
+ lib_widget, folder_widget = self.__library_widgets(trans, request.user, len(current_samples),
+ libraries, None, lib_id, folder_id, **kwd)
+ current_samples.append(dict(name=row[0],
+ barcode='',
+ library=None,
+ folder=None,
+ lib_widget=lib_widget,
+ folder_widget=folder_widget,
+ field_values=row[3:]))
+ return trans.fill_template( '/requests/common/show_request.mako',
+ cntrller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples=current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details,
+ edit_mode=edit_mode)
+ except:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ id=trans.security.encode_id(request.id),
+ status='error',
+ message='Error in importing samples file' ))
+
+ def __validate_barcode(self, trans, sample, barcode):
+ '''
+ This method makes sure that the given barcode about to be assigned to
+ the given sample is gobally unique. That is, barcodes must be unique
+ across requests in Galaxy LIMS
+ '''
+ message = ''
+ for index in range(len(sample.request.samples)):
+ # check for empty bar code
+ if not barcode.strip():
+ message = 'Please fill the barcode for sample <b>%s</b>.' % sample.name
+ break
+ # check all the saved bar codes
+ all_samples = trans.sa_session.query( trans.app.model.Sample )
+ for s in all_samples:
+ if barcode == s.bar_code:
+ if sample.id == s.id:
+ continue
+ else:
+ message = '''The bar code <b>%s</b> of sample <b>%s</b>
+ belongs another sample. The sample bar codes must be
+ unique throughout the system''' % \
+ (barcode, sample.name)
+ break
+ if message:
+ break
+ return message
+
+
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def delete_sample(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', 0 ) ) )
+ current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd )
+ sample_index = int(params.get('sample_id', 0))
+ sample_name = current_samples[sample_index]['name']
+ s = request.has_sample(sample_name)
+ if s:
+ trans.sa_session.delete( s.values )
+ trans.sa_session.delete( s )
+ trans.sa_session.flush()
+ del current_samples[sample_index]
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ id=trans.security.encode_id(request.id),
+ status='done',
+ message='Sample <b>%s</b> has been deleted.' % sample_name ))
+ return trans.fill_template( '/requests/common/show_request.mako',
+ controller=cntrller,
+ request=request,
+ request_details=self.request_details(trans, request.id),
+ current_samples = current_samples,
+ sample_copy=self.__copy_sample(current_samples),
+ details=details,
+ edit_mode=edit_mode)
+ def request_details(self, trans, id):
+ '''
+ Shows the request details
+ '''
+ request = trans.sa_session.query( trans.app.model.Request ).get( id )
+ # list of widgets to be rendered on the request form
+ request_details = []
+ # main details
+ request_details.append(dict(label='User',
+ value=str(request.user.email),
+ helptext=''))
+ request_details.append(dict(label='Description',
+ value=request.desc,
+ helptext=''))
+ request_details.append(dict(label='Type',
+ value=request.type.name,
+ helptext=''))
+ request_details.append(dict(label='State',
+ value=request.state(),
+ helptext=''))
+ request_details.append(dict(label='Date created',
+ value=request.create_time,
+ helptext=''))
+ # form fields
+ for index, field in enumerate(request.type.request_form.fields):
+ if field['required']:
+ req = 'Required'
+ else:
+ req = 'Optional'
+ if field['type'] == 'AddressField':
+ if request.values.content[index]:
+ request_details.append(dict(label=field['label'],
+ value=trans.sa_session.query( trans.app.model.UserAddress ).get( int( request.values.content[index] ) ).get_html(),
+ helptext=field['helptext']+' ('+req+')'))
+ else:
+ request_details.append(dict(label=field['label'],
+ value=None,
+ helptext=field['helptext']+' ('+req+')'))
+ else:
+ request_details.append(dict(label=field['label'],
+ value=request.values.content[index],
+ helptext=field['helptext']+' ('+req+')'))
+ if request.notify:
+ notify = 'Yes'
+ else:
+ notify = 'No'
+ request_details.append(dict(label='Send email notification once the sequencing request is complete',
+ value=notify,
+ helptext=''))
+ return request_details
+ @web.expose
+ @web.require_login( "create/submit sequencing requests" )
+ def sample_events(self, trans, **kwd):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ try:
+ sample_id = int(params.get('sample_id', False))
+ sample = trans.sa_session.query( trans.app.model.Sample ).get( sample_id )
+ except:
+ message = "Invalid sample ID"
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message=message) )
+ events_list = []
+ all_events = sample.events
+ for event in all_events:
+ events_list.append((event.state.name, event.state.desc,
+ time_ago(event.update_time),
+ event.comment))
+ widgets, title = self.__change_state_widgets(trans, sample)
+ return trans.fill_template( '/requests/common/sample_events.mako',
+ cntrller=cntrller,
+ events_list=events_list,
+ sample=sample, widgets=widgets, title=title)
+ def __change_state_widgets(self, trans, sample):
+ possible_states = sample.request.type.states
+ curr_state = sample.current_state()
+ states_input = SelectField('select_state')
+ for state in possible_states:
+ if curr_state.name == state.name:
+ states_input.add_option(state.name+' (Current)', state.id, selected=True)
+ else:
+ states_input.add_option(state.name, state.id)
+ widgets = []
+ widgets.append(('Select the new state of the sample from the list of possible state(s)',
+ states_input))
+ widgets.append(('Comments', TextArea('comment')))
+ title = 'Change current state'
+ return widgets, title
+ @web.expose
+ @web.require_admin
+ def show_datatx_page( self, trans, **kwd ):
+ params = util.Params( kwd )
+ cntrller = util.restore_text( params.get( 'cntrller', 'requests' ) )
+ message = util.restore_text( params.get( 'message', '' ) )
+ status = params.get( 'status', 'done' )
+ try:
+ sample = trans.sa_session.query( trans.app.model.Sample ).get( trans.security.decode_id( kwd['sample_id'] ) )
+ except:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ status='error',
+ message="Invalid sample ID") )
+ # check if a library and folder has been set for this sample yet.
+ if not sample.library or not sample.folder:
+ return trans.response.send_redirect( web.url_for( controller=cntrller,
+ action='list',
+ operation='show',
+ status='error',
+ message="Set a data library and folder for <b>%s</b> to transfer dataset(s)." % sample.name,
+ id=trans.security.encode_id(sample.request.id) ) )
+ if params.get( 'folder_path', '' ):
+ folder_path = util.restore_text( params.get( 'folder_path', '' ) )
+ else:
+ if len(sample.dataset_files):
+ folder_path = os.path.dirname(sample.dataset_files[-1]['filepath'][:-1])
+ else:
+ folder_path = util.restore_text( sample.request.type.datatx_info.get('data_dir', '') )
+ if folder_path and folder_path[-1] != os.sep:
+ folder_path += os.sep
+ if not sample.request.type.datatx_info['host'] or not sample.request.type.datatx_info['username'] \
+ or not sample.request.type.datatx_info['password']:
+ status = 'error'
+ message = 'The sequencer login information is incomplete. Click on the <b>Sequencer information</b> to add login details.'
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller=cntrller, sample=sample,
+ dataset_files=sample.dataset_files,
+ message=message, status=status, files=[],
+ folder_path=folder_path )
--- a/templates/requests/events.mako
+++ /dev/null
@@ -1,39 +0,0 @@
-<%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 message:
- ${render_msg( message, status )}
-%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>
--- /dev/null
+++ b/templates/requests/common/sample_state.mako
@@ -0,0 +1,5 @@
+<%def name="render_sample_state( cntrller, sample )">
+ <a href="${h.url_for( controller='requests_common', cntrller=cntrller, action='sample_events', sample_id=sample.id)}">${sample.current_state().name}</a>
+</%def>
+
+${render_sample_state( cntrller, sample )}
--- /dev/null
+++ b/templates/requests/common/get_data.mako
@@ -0,0 +1,239 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<script type="text/javascript">
+$(document).ready(function(){
+ //hide the all of the element with class msg_body
+ $(".msg_body").hide();
+ //toggle the componenet with class msg_body
+ $(".msg_head").click(function(){
+ $(this).next(".msg_body").slideToggle(450);
+ });
+});
+
+
+
+
+</script>
+
+<script type="text/javascript">
+ function display_file_details(sample_id, folder_path)
+ {
+ var w = document.get_data.files_list.selectedIndex;
+ var selected_value = document.get_data.files_list.options[w].value;
+ var cell = $("#file_details");
+ if(selected_value.charAt(selected_value.length-1) != '/')
+ {
+ // Make ajax call
+ $.ajax( {
+ type: "POST",
+ url: "${h.url_for( controller='requests_admin', action='get_file_details' )}",
+ dataType: "json",
+ data: { id: sample_id, folder_path: document.get_data.folder_path.value+selected_value },
+ success : function ( data ) {
+ cell.html( '<label>'+data+'</label>' )
+ }
+ });
+ }
+ else
+ {
+ cell.html( '' )
+ }
+
+
+ }
+</script>
+
+<script type="text/javascript">
+ function open_folder1(sample_id, folder_path)
+ {
+ var w = document.get_data.files_list.selectedIndex;
+ var selected_value = document.get_data.files_list.options[w].value;
+ var cell = $("#file_details");
+ if(selected_value.charAt(selected_value.length-1) == '/')
+ {
+ document.get_data.folder_path.value = document.get_data.folder_path.value+selected_value
+ // Make ajax call
+ $.ajax( {
+ type: "POST",
+ url: "${h.url_for( controller='requests_admin', action='open_folder' )}",
+ dataType: "json",
+ data: { id: sample_id, folder_path: document.get_data.folder_path.value },
+ success : function ( data ) {
+ document.get_data.files_list.options.length = 0
+ for(i=0; i<data.length; i++)
+ {
+ var newOpt = new Option(data[i], data[i]);
+ document.get_data.files_list.options[i] = newOpt;
+ }
+ //cell.html( '<label>'+data+'</label>' )
+
+ }
+ });
+ }
+ else
+ {
+ cell.html( '' )
+ }
+ }
+</script>
+
+
+<style type="text/css">
+.msg_head {
+ padding: 0px 0px;
+ cursor: pointer;
+}
+
+}
+</style>
+
+
+<h2>Data transfer from Sequencer</h2>
+<h3>Sample "${sample.name}" of Request "${sample.request.name}"</h3>
+<br/>
+<br/>
+
+<ul class="manage-table-actions">
+ %if sample.request.submitted() and sample.inprogress_dataset_files():
+ <li>
+ <a class="action-button" href="${h.url_for( controller='requests_common', cntrller=cntrller, action='show_datatx_page', sample_id=trans.security.encode_id(sample.id) )}">
+ <span>Refresh this page</span></a>
+ </li>
+ %endif
+ %if cntrller == 'requests_admin' and trans.user_is_admin():
+ <li>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_request_types', operation='view', id=trans.security.encode_id(sample.request.type.id) )}">
+ <span>Sequencer information</span></a>
+ </li>
+
+ <li>
+ <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller='library_admin', id=trans.security.encode_id( sample.library.id ) )}">
+ <span>${sample.library.name} Data Library</span></a>
+ </li>
+ %else:
+ <li>
+ <a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">
+ <span>${sample.library.name} Data Library</span></a>
+ </li>
+ %endif
+ <li>
+ <a class="action-button" href="${h.url_for( controller=cntrller, action='list', operation='show', id=trans.security.encode_id(sample.request.id) )}">
+ <span>Browse this request</span></a>
+ </li>
+</ul>
+
+<div class="toolForm">
+ %if len(dataset_files):
+ <div class="form-row">
+ <h4>Sample Dataset(s)</h4>
+ %if sample.untransferred_dataset_files() and cntrller == 'requests_admin':
+ <div class="form-row">
+ <ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', start_transfer_button=True, sample_id=sample.id )}">
+ <span>Start transfer</span></a>
+ </li>
+ </ul>
+ </div>
+ %endif
+ <div class="form-row">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>Dataset File</th>
+ <th>Transfer Status</th>
+ <th></th>
+ </tr>
+ <thead>
+ <tbody>
+ %for dataset_index, dataset_file in enumerate(dataset_files):
+ ${sample_dataset_files( dataset_index, dataset_file['name'], dataset_file['status'] )}
+ %endfor
+ </tbody>
+ </table>
+ </div>
+ </div>
+ %else:
+ <div class="form-row">
+ There are no dataset files associated with this sample.
+ </div>
+ %endif
+
+ <br/>
+ <br/>
+
+ %if cntrller == 'requests_admin' and trans.user_is_admin():
+ <form name="get_data" id="get_data" action="${h.url_for( controller='requests_admin', cntrller=cntrller, action='get_data', sample_id=sample.id)}" method="post" >
+ <div class="form-row">
+ ##<div class="toolFormTitle">Select files for transfer</div>
+ <h4>Select files for transfer</h4>
+ <div style="width: 60%;">
+ <div class="form-row">
+ <label>Folder path on the sequencer:</label>
+ <input type="text" name="folder_path" value="${folder_path}" size="100"/>
+ <input type="submit" name="browse_button" value="List contents"/>
+ ##<input type="submit" name="open_folder" value="Open folder"/>
+ <input type="submit" name="folder_up" value="Up"/>
+ </div>
+ <div class="form-row">
+ <select name="files_list" id="files_list" style="max-width: 98%; width: 98%; height: 150px; font-size: 100%;" ondblclick="open_folder1(${sample.id}, '${folder_path}')" onChange="display_file_details(${sample.id}, '${folder_path}')" multiple>
+ %for index, f in enumerate(files):
+ <option value="${f}">${f}</option>
+ %endfor
+ </select>
+ <br/>
+ <div id="file_details" class="toolParamHelp" style="clear: both;">
+
+ </div>
+ </div>
+ <div class="form-row">
+ <div class="toolParamHelp" style="clear: both;">
+ After selecting dataset(s), be sure to click on the <b>Start transfer</b> button.
+ Once the transfer is complete the dataset(s) will show up on this page.
+ </div>
+ <input type="submit" name="select_files_button" value="Select"/>
+ </div>
+ </div>
+ </div>
+ </form>
+ %endif
+</div>
+
+
+
+
+<%def name="sample_dataset_files( dataset_index, dataset_name, status )">
+ <tr>
+
+ <td>
+ %if cntrller == 'requests_admin' and trans.user_is_admin():
+ <label class="msg_head"><a href="${h.url_for( controller='requests_admin', action='dataset_details', sample_id=trans.security.encode_id(sample.id), dataset_index=dataset_index )}">${dataset_name}</a></label>
+ %else:
+ ${dataset_name}
+ %endif
+ </td>
+ <td>
+ %if status not in [sample.transfer_status.NOT_STARTED, sample.transfer_status.COMPLETE]:
+ <i>${status}</i>
+ %else:
+ ${status}
+ %endif
+ </td>
+ ##<td></td>
+ %if status == sample.transfer_status.NOT_STARTED and cntrller == 'requests_admin' and trans.user_is_admin():
+ <td>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='get_data', sample_id=sample.id, remove_dataset_button=True, dataset_index=dataset_index )}">
+ <img src="${h.url_for('/static/images/delete_icon.png')}" />
+ <span></span></a>
+ </td>
+ %else:
+ <td></td>
+ %endif
+ </tr>
+</%def>
--- a/templates/admin/requests/events.mako
+++ /dev/null
@@ -1,36 +0,0 @@
-<%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 message:
- ${render_msg( message, status )}
-%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>
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -95,7 +95,7 @@ class RequestsGrid( grids.Grid ):
NameColumn( "Name",
key="name",
model_class=model.Request,
- link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="show", id=item.id ) ) ),
attach_popup=True,
filterable="advanced" ),
DescriptionColumn( "Description",
@@ -103,7 +103,7 @@ class RequestsGrid( grids.Grid ):
model_class=model.Request,
filterable="advanced" ),
SamplesColumn( "Sample(s)",
- link=( lambda item: iff( item.deleted, None, dict( operation="show_request", id=item.id ) ) ), ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="show", id=item.id ) ) ), ),
TypeColumn( "Type",
link=( lambda item: iff( item.deleted, None, dict( operation="view_type", id=item.type.id ) ) ), ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
@@ -137,7 +137,8 @@ class RequestsGrid( grids.Grid ):
grids.GridOperation( "Undelete", condition=( lambda item: item.deleted ) ),
]
global_actions = [
- grids.GridAction( "Create new request", dict( controller='requests_admin',
+ grids.GridAction( "Create new request", dict( controller='requests_common',
+ cntrller='requests_admin',
action='new',
select_request_type='True' ) )
]
@@ -218,6 +219,58 @@ class RequestsAdmin( BaseController ):
@web.require_admin
def index( self, trans ):
return trans.fill_template( "/admin/requests/index.mako" )
+
+ @web.expose
+ @web.require_admin
+ def list( self, trans, **kwd ):
+ '''
+ List all request made by the current user
+ '''
+ if 'operation' in kwd:
+ operation = kwd['operation'].lower()
+ if not kwd.get( 'id', None ):
+ return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ action='list',
+ status='error',
+ message="Invalid request ID") )
+ if operation == "show":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='show',
+ **kwd ) )
+ elif operation == "submit":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='submit',
+ **kwd ) )
+ elif operation == "delete":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='delete',
+ **kwd ) )
+ elif operation == "undelete":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='undelete',
+ **kwd ) )
+ elif operation == "edit":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='edit',
+ show=True, **kwd ) )
+ elif operation == "events":
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='events',
+ **kwd ) )
+ elif operation == "reject":
+ return self.__reject_request( trans, **kwd )
+ elif operation == "view_type":
+ return self.__view_request_type( trans, **kwd )
+ elif operation == "upload_datasets":
+ return self.__upload_datasets( trans, **kwd )
+ # Render the grid view
+ return self.request_grid( trans, **kwd )
@web.json
def get_file_details( self, trans, id=None, folder_path=None ):
@@ -246,239 +299,6 @@ class RequestsAdmin( BaseController ):
sample = trans.sa_session.query( self.app.model.Sample ).get( int(id) )
return self.__get_files(trans, sample, folder_path)
-
- @web.json
- def sample_state_updates( self, trans, ids=None, states=None ):
- # Avoid caching
- trans.response.headers['Pragma'] = 'no-cache'
- trans.response.headers['Expires'] = '0'
- # Create new HTML for any that have changed
- rval = {}
- if ids is not None and states is not None:
- ids = map( int, ids.split( "," ) )
- states = states.split( "," )
- for id, state in zip( ids, states ):
- sample = trans.sa_session.query( self.app.model.Sample ).get( id )
- if sample.current_state().name != state:
- rval[id] = {
- "state": sample.current_state().name,
- "datasets": len(sample.dataset_files),
- "html_state": unicode( trans.fill_template( "requests/sample_state.mako", sample=sample ), 'utf-8' ),
- "html_datasets": unicode( trans.fill_template( "requests/sample_datasets.mako", trans=trans, sample=sample ), 'utf-8' )
- }
- return rval
-
- @web.expose
- @web.require_admin
- def list( self, trans, **kwd ):
- '''
- List all request made by the current user
- '''
- if 'operation' in kwd:
- operation = kwd['operation'].lower()
- if not kwd.get( 'id', None ):
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message="Invalid request ID") )
- if operation == "show_request":
- return self.__show_request( trans, **kwd )
- elif operation == "submit":
- return self.__submit_request( trans, **kwd )
- elif operation == "delete":
- return self.__delete_request( trans, **kwd )
- elif operation == "undelete":
- return self.__undelete_request( trans, **kwd )
- elif operation == "edit":
- 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 )
- elif operation == "upload_datasets":
- return self.__upload_datasets( trans, **kwd )
- # Render the grid view
- return self.request_grid( trans, **kwd )
- @web.expose
- @web.require_admin
- def edit(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', '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', '')):
- message = 'Please enter the <b>Name</b> of the request'
- kwd['status'] = 'error'
- kwd['message'] = message
- kwd['show'] = 'True'
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='edit',
- **kwd) )
- request = self.__save_request(trans, request, **kwd)
- message = '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=message ,
- 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',
- message=message ,
- status='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']) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message) )
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- select_request_type = self.__select_request_type(trans, request.type.id)
- # list of widgets to be rendered on the request form
- widgets = []
- if util.restore_text( params.get( 'name', '' ) ):
- name = util.restore_text( params.get( 'name', '' ) )
- else:
- name = request.name
- widgets.append(dict(label='Name',
- widget=TextField('name', 40, name),
- helptext='(Required)'))
- if util.restore_text( params.get( 'desc', '' ) ):
- desc = util.restore_text( params.get( 'desc', '' ) )
- else:
- desc = request.desc
- widgets.append(dict(label='Description',
- widget=TextField('desc', 40, desc),
- helptext='(Optional)'))
- widgets = widgets + request.type.request_form.get_widgets( request.user, request.values.content, **kwd )
- widgets.append(dict(label='Send email notification once the sequencing request is complete',
- widget=CheckboxField('email_notify', request.notify),
- helptext=''))
- return trans.fill_template( '/admin/requests/edit_request.mako',
- select_request_type=select_request_type,
- request_type=request.type,
- request=request,
- widgets=widgets,
- message=message,
- status=status)
- return self.__show_request_form(trans)
- def __delete_request(self, trans, **kwd):
- id_list = util.listify( kwd['id'] )
- for id in id_list:
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message,
- **kwd) )
- request.deleted = True
- trans.sa_session.add( request )
- # delete all the samples belonging to this request
- for s in request.samples:
- s.deleted = True
- trans.sa_session.add( s )
- trans.sa_session.flush()
- message = '%i request(s) has been deleted.' % len(id_list)
- status = 'done'
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status=status,
- message=message) )
- def __undelete_request(self, trans, **kwd):
- id_list = util.listify( kwd['id'] )
- for id in id_list:
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(id) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message,
- **kwd) )
- request.deleted = False
- trans.sa_session.add( request )
- # undelete all the samples belonging to this request
- for s in request.samples:
- s.deleted = False
- trans.sa_session.add( s )
- trans.sa_session.flush()
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='done',
- message='%i request(s) has been undeleted.' % len(id_list) ) )
- def __submit_request(self, trans, **kwd):
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
- except:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message,
- **kwd) )
- message = self.__validate(trans, request)
- if message:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='edit',
- status = 'error',
- message=message,
- id=trans.security.encode_id(request.id) ) )
- # change the request state to 'Submitted'
- if request.user.email is not trans.user:
- comments = "Request submitted 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 created.')
- trans.sa_session.add( event )
- trans.sa_session.add( request )
- trans.sa_session.flush()
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- id=trans.security.encode_id(request.id),
- status='done',
- message='The request <b>%s</b> has been submitted.' % request.name
- ) )
def __reject_request(self, trans, **kwd):
try:
request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
@@ -526,759 +346,10 @@ class RequestsAdmin( BaseController ):
status='done',
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:
- message = "Invalid request ID"
- log.warn( message )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message,
- **kwd) )
- events_list = []
- all_events = request.events
- for event in all_events:
- events_list.append((event.state, time_ago(event.update_time), event.comment))
- return trans.fill_template( '/admin/requests/events.mako',
- events_list=events_list, request=request)
-
def __upload_datasets(self, trans, **kwd):
return trans.fill_template( '/admin/requests/upload_datasets.mako' )
-#
-#---- Request Creation ----------------------------------------------------------
-#
- def __select_request_type(self, trans, rtid):
- requesttype_list = trans.user.accessible_request_types(trans)
- rt_ids = ['none']
- for rt in requesttype_list:
- if not rt.deleted:
- rt_ids.append(str(rt.id))
- select_reqtype = SelectField('select_request_type',
- refresh_on_change=True,
- refresh_on_change_values=rt_ids[1:])
- if rtid == 'none':
- select_reqtype.add_option('Select one', 'none', selected=True)
- else:
- select_reqtype.add_option('Select one', 'none')
- for rt in requesttype_list:
- if not rt.deleted:
- if rtid == rt.id:
- select_reqtype.add_option(rt.name, rt.id, selected=True)
- else:
- select_reqtype.add_option(rt.name, rt.id)
- return select_reqtype
- @web.expose
- @web.require_admin
- def new(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- if params.get('select_request_type', False) == 'True':
- return trans.fill_template( '/admin/requests/new_request.mako',
- select_request_type=self.__select_request_type(trans, 'none'),
- widgets=[],
- message=message,
- status=status)
- elif params.get('create', False) == 'True':
- if params.get('create_request_button', False) == 'Save' \
- or params.get('create_request_samples_button', False) == 'Add samples':
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- if not util.restore_text(params.get('name', '')) \
- or util.restore_text(params.get('select_user', '')) == unicode('none'):
- message = 'Please enter the <b>Name</b> of the request and the <b>user</b> on behalf of whom this request will be submitted before saving this request'
- kwd['create'] = 'True'
- kwd['status'] = 'error'
- kwd['message'] = message
- kwd['create_request_button'] = None
- kwd['create_request_samples_button'] = None
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='new',
- **kwd) )
- request = self.__save_request(trans, None, **kwd)
- message = 'The new request named %s has been created' % request.name
- if params.get('create_request_button', False) == 'Save':
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- message=message ,
- status='done') )
- elif params.get('create_request_samples_button', False) == 'Add samples':
- new_kwd = {}
- new_kwd['id'] = trans.security.encode_id(request.id)
- new_kwd['operation'] = 'show_request'
- new_kwd['add_sample'] = True
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- message=message ,
- status='done',
- **new_kwd) )
- else:
- return self.__show_request_form(trans, **kwd)
- elif params.get('refresh', False) == 'true':
- return self.__show_request_form(trans, **kwd)
- def __show_request_form(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- try:
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- except:
- return trans.fill_template( '/admin/requests/new_request.mako',
- select_request_type=self.__select_request_type(trans, 'none'),
- widgets=[],
- message=message,
- status=status)
- form_values = None
- select_request_type = self.__select_request_type(trans, request_type.id)
- # user
- user_id = params.get( 'select_user', 'none' )
- try:
- user = trans.sa_session.query( trans.app.model.User ).get( int( user_id ) )
- except:
- user = None
- # list of widgets to be rendered on the request form
- widgets = []
- widgets.append(dict(label='Select user',
- widget=self.__select_user(trans, user_id),
- helptext='The request would be submitted on behalf of this user (Required)'))
- widgets.append(dict(label='Name of the Experiment',
- widget=TextField('name', 40,
- util.restore_text( params.get( 'name', '' ) )),
- helptext='(Required)'))
- widgets.append(dict(label='Description',
- widget=TextField('desc', 40,
- util.restore_text( params.get( 'desc', '' ) )),
- helptext='(Optional)'))
- widgets = widgets + request_type.request_form.get_widgets( user, **kwd )
- widgets.append(dict(label='Send email notification once the sequencing request is complete',
- widget=CheckboxField('email_notify', False),
- helptext='Email would be sent to the lab admin and the user for whom this request has been created.'))
- return trans.fill_template( '/admin/requests/new_request.mako',
- select_request_type=select_request_type,
- request_type=request_type,
- widgets=widgets,
- message=message,
- status=status)
- def __select_user(self, trans, userid):
- user_list = trans.sa_session.query( trans.app.model.User )\
- .order_by( trans.app.model.User.email.asc() )
- user_ids = ['none']
- for user in user_list:
- if not user.deleted:
- user_ids.append(str(user.id))
- select_user = SelectField('select_user',
- refresh_on_change=True,
- refresh_on_change_values=user_ids[1:])
- if userid == 'none':
- select_user.add_option('Select one', 'none', selected=True)
- else:
- select_user.add_option('Select one', 'none')
- for user in user_list:
- if not user.deleted:
- if userid == str(user.id):
- select_user.add_option(user.email, user.id, selected=True)
- else:
- select_user.add_option(user.email, user.id)
- return select_user
- def __validate(self, trans, request):
- '''
- Validates the request entered by the user
- '''
- if not request.samples:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='show_request',
- message='Please add one or more samples to this request before submitting.',
- status='error',
- id=trans.security.encode_id(request.id)) )
- empty_fields = []
- # check rest of the fields of the form
- for index, field in enumerate(request.type.request_form.fields):
- if field['required'] == 'required' and request.values.content[index] in ['', None]:
- empty_fields.append(field['label'])
- if empty_fields:
- message = 'Fill the following fields of the request <b>%s</b> before submitting<br/>' % request.name
- for ef in empty_fields:
- message = message + '<b>' +ef + '</b><br/>'
- return message
- return None
- def __save_request(self, trans, request=None, **kwd):
- '''
- This method saves a new request if request_id is None.
- '''
- params = util.Params( kwd )
- request_type = trans.sa_session.query( trans.app.model.RequestType ).get( int( params.select_request_type ) )
- if request:
- user = request.user
- else:
- user = trans.sa_session.query( trans.app.model.User ).get( int( params.get( 'select_user', '' ) ) )
- name = util.restore_text(params.get('name', ''))
- desc = util.restore_text(params.get('desc', ''))
- notify = CheckboxField.is_checked( params.get('email_notify', '') )
- # fields
- values = []
- for index, field in enumerate(request_type.request_form.fields):
- if field['type'] == 'AddressField':
- value = util.restore_text(params.get('field_%i' % index, ''))
- if value == 'new':
- # save this new address in the list of this user's addresses
- user_address = trans.app.model.UserAddress( user=user )
- user_address.desc = util.restore_text(params.get('field_%i_short_desc' % index, ''))
- user_address.name = util.restore_text(params.get('field_%i_name' % index, ''))
- user_address.institution = util.restore_text(params.get('field_%i_institution' % index, ''))
- user_address.address = util.restore_text(params.get('field_%i_address1' % index, ''))+' '+util.restore_text(params.get('field_%i_address2' % index, ''))
- user_address.city = util.restore_text(params.get('field_%i_city' % index, ''))
- user_address.state = util.restore_text(params.get('field_%i_state' % index, ''))
- user_address.postal_code = util.restore_text(params.get('field_%i_postal_code' % index, ''))
- user_address.country = util.restore_text(params.get('field_%i_country' % index, ''))
- user_address.phone = util.restore_text(params.get('field_%i_phone' % index, ''))
- trans.sa_session.add( user_address )
- trans.sa_session.flush()
- trans.sa_session.refresh( trans.user )
- values.append(int(user_address.id))
- elif value == unicode('none'):
- values.append('')
- else:
- values.append(int(value))
- elif field['type'] == 'CheckboxField':
- values.append(CheckboxField.is_checked( params.get('field_%i' % index, '') ))
- else:
- values.append(util.restore_text(params.get('field_%i' % index, '')))
- form_values = trans.app.model.FormValues(request_type.request_form, values)
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- if not request:
- request = trans.app.model.Request(name, desc, request_type,
- user, form_values, notify)
- 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
- request.type = request_type
- request.user = user
- request.notify = notify
- request.values = form_values
- trans.sa_session.add( request )
- trans.sa_session.flush()
- return request
-#
-#---- Request Page ----------------------------------------------------------
-#
- def __show_request(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- add_sample = params.get('add_sample', False)
- try:
- request = trans.sa_session.query( trans.app.model.Request ).get( trans.security.decode_id(kwd['id']) )
- except:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message="Invalid request ID") )
- # get all data libraries accessible to this user
- libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
- current_samples = []
- for i, s in enumerate(request.samples):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
- current_samples.append(dict(name=s.name,
- barcode=s.bar_code,
- library=s.library,
- folder=s.folder,
- dataset_files=s.dataset_files,
- field_values=s.values.content,
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- if add_sample:
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples)+1,
- libraries, None, **kwd)
- current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
- barcode='',
- library=None,
- folder=None,
- dataset_files=[],
- field_values=['' for field in request.type.sample_form.fields],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details='hide', edit_mode=util.restore_text( params.get( 'edit_mode', 'False' ) ),
- message=message, status=status )
- def __library_widgets(self, trans, user, sample_index, libraries, sample=None, lib_id=None, folder_id=None, **kwd):
- '''
- This method creates the data library & folder selectbox for creating &
- editing samples. First we get a list of all the libraries accessible to
- the current user and display it in a selectbox. If the user has selected an
- existing library then display all the accessible sub folders of the selected
- data library.
- '''
- params = util.Params( kwd )
- # data library selectbox
- if not lib_id:
- lib_id = params.get( "sample_%i_library_id" % sample_index, 'none' )
- selected_lib = None
- if sample and lib_id == 'none':
- if sample.library:
- lib_id = str(sample.library.id)
- selected_lib = sample.library
- # create data library selectbox with refresh on change enabled
- lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
- lib_widget = SelectField( "sample_%i_library_id" % sample_index,
- refresh_on_change=True,
- refresh_on_change_values=lib_id_list )
- # fill up the options in the Library selectbox
- # first option 'none' is the value for "Select one" option
- if lib_id == 'none':
- lib_widget.add_option('Select one', 'none', selected=True)
- else:
- lib_widget.add_option('Select one', 'none')
- # all the libraries available to the selected user
- for lib, hidden_folder_ids in libraries.items():
- if str(lib.id) == str(lib_id):
- lib_widget.add_option(lib.name, lib.id, selected=True)
- selected_lib, selected_hidden_folder_ids = lib, hidden_folder_ids.split(',')
- else:
- lib_widget.add_option(lib.name, lib.id)
- lib_widget.refresh_on_change_values.append(lib.id)
- # create the folder selectbox
- folder_widget = SelectField( "sample_%i_folder_id" % sample_index )
- # when editing a request, either the user has already selected a subfolder or not
- if sample:
- if sample.folder:
- current_fid = sample.folder.id
- else:
- # when a folder not yet associated with the request then the
- # the current folder is set to the root_folder of the
- # parent data library if present.
- if sample.library:
- current_fid = sample.library.root_folder.id
- else:
- current_fid = params.get( "sample_%i_folder_id" % sample_index, 'none' )
- else:
- if folder_id:
- current_fid = folder_id
- else:
- current_fid = 'none'
- # first option
- if lib_id == 'none':
- folder_widget.add_option('Select one', 'none', selected=True)
- else:
- folder_widget.add_option('Select one', 'none')
- if selected_lib:
- # get all show-able folders for the selected library
- showable_folders = trans.app.security_agent.get_showable_folders( user, user.all_roles(),
- selected_lib,
- [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ],
- selected_hidden_folder_ids )
- for f in showable_folders:
- if str(f.id) == str(current_fid):
- folder_widget.add_option(f.name, f.id, selected=True)
- else:
- folder_widget.add_option(f.name, f.id)
- return lib_widget, folder_widget
- def __update_samples(self, trans, request, **kwd):
- '''
- This method retrieves all the user entered sample information and
- returns an list of all the samples and their field values
- '''
- params = util.Params( kwd )
- details = params.get( 'details', 'hide' )
- edit_mode = params.get( 'edit_mode', 'False' )
- # get all data libraries accessible to this user
- libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
-
- current_samples = []
- for i, s in enumerate(request.samples):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, i, libraries, s, **kwd)
- current_samples.append(dict(name=s.name,
- barcode=s.bar_code,
- library=s.library,
- folder=s.folder,
- field_values=s.values.content,
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- if edit_mode == 'False':
- sample_index = len(request.samples)
- else:
- sample_index = 0
- while True:
- lib_id = None
- folder_id = None
- if params.get( 'sample_%i_name' % sample_index, '' ):
- # data library
- try:
- library = trans.sa_session.query( trans.app.model.Library ).get( int( params.get( 'sample_%i_library_id' % sample_index, None ) ) )
- lib_id = library.id
- except:
- library = None
- # folder
- try:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( int( params.get( 'sample_%i_folder_id' % sample_index, None ) ) )
- folder_id = folder.id
- except:
- if library:
- folder = library.root_folder
- else:
- folder = None
- sample_info = dict( name=util.restore_text( params.get( 'sample_%i_name' % sample_index, '' ) ),
- barcode=util.restore_text( params.get( 'sample_%i_barcode' % sample_index, '' ) ),
- library=library,
- folder=folder)
- sample_info['field_values'] = []
- for field_index in range(len(request.type.sample_form.fields)):
- sample_info['field_values'].append(util.restore_text( params.get( 'sample_%i_field_%i' % (sample_index, field_index), '' ) ))
- if edit_mode == 'False':
- sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans, request.user,
- sample_index, libraries,
- None, lib_id, folder_id, **kwd)
- current_samples.append(sample_info)
- else:
- sample_info['lib_widget'], sample_info['folder_widget'] = self.__library_widgets(trans,
- request.user,
- sample_index,
- libraries,
- request.samples[sample_index],
- **kwd)
- current_samples[sample_index] = sample_info
- sample_index = sample_index + 1
- else:
- break
- return current_samples, details, edit_mode, libraries
- def __copy_sample(self, current_samples):
- copy_list = SelectField('copy_sample')
- copy_list.add_option('None', -1, selected=True)
- for i, s in enumerate(current_samples):
- copy_list.add_option(s['name'], i)
- return copy_list
- def __import_samples(self, trans, request, current_samples, details, libraries, **kwd):
- '''
- This method reads the samples csv file and imports all the samples
- The format of the csv file is:
- SampleName,DataLibrary,DataLibraryFolder,Field1,Field2....
- '''
- try:
- params = util.Params( kwd )
- edit_mode = params.get( 'edit_mode', 'False' )
- file_obj = params.get('file_data', '')
- reader = csv.reader(file_obj.file)
- for row in reader:
- lib_id = None
- folder_id = None
- lib = trans.sa_session.query( trans.app.model.Library ) \
- .filter( and_( trans.app.model.Library.table.c.name==row[1], \
- trans.app.model.Library.table.c.deleted==False ) )\
- .first()
- if lib:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ) \
- .filter( and_( trans.app.model.LibraryFolder.table.c.name==row[2], \
- trans.app.model.LibraryFolder.table.c.deleted==False ) )\
- .first()
- if folder:
- lib_id = lib.id
- folder_id = folder.id
- lib_widget, folder_widget = self.__library_widgets(trans, request.user, len(current_samples),
- libraries, None, lib_id, folder_id, **kwd)
- current_samples.append(dict(name=row[0],
- barcode='',
- library=None,
- folder=None,
- lib_widget=lib_widget,
- folder_widget=folder_widget,
- field_values=row[3:]))
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- except:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='show_request',
- id=trans.security.encode_id(request.id),
- status='error',
- message='Error in importing samples file' ))
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def show_request(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', '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) )
- # get the user entered sample details
- current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd )
- if params.get('import_samples_button', False) == 'Import samples':
- return self.__import_samples(trans, request, current_samples, details, libraries, **kwd)
- elif params.get('add_sample_button', False) == 'Add New':
- # add an empty or filled sample
- # if the user has selected a sample no. to copy then copy the contents
- # of the src sample to the new sample else an empty sample
- src_sample_index = int(params.get( 'copy_sample', -1 ))
- # get the number of new copies of the src sample
- num_sample_to_copy = int(params.get( 'num_sample_to_copy', 1 ))
- if src_sample_index == -1:
- for ns in range(num_sample_to_copy):
- # empty sample
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples),
- libraries, None, **kwd)
- current_samples.append(dict(name='Sample_%i' % (len(current_samples)+1),
- barcode='',
- library=None,
- folder=None,
- field_values=['' for field in request.type.sample_form.fields],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- else:
- src_library_id = current_samples[src_sample_index]['lib_widget'].get_selected()[1]
- src_folder_id = current_samples[src_sample_index]['folder_widget'].get_selected()[1]
- for ns in range(num_sample_to_copy):
- lib_widget, folder_widget = self.__library_widgets(trans, request.user,
- len(current_samples),
- libraries, sample=None,
- lib_id=src_library_id,
- folder_id=src_folder_id,
- **kwd)
- current_samples.append(dict(name=current_samples[src_sample_index]['name']+'_%i' % (len(current_samples)+1),
- barcode='',
- library_id='none',
- folder_id='none',
- field_values=[val for val in current_samples[src_sample_index]['field_values']],
- lib_widget=lib_widget,
- folder_widget=folder_widget))
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- elif params.get('save_samples_button', False) == 'Save':
- # check for duplicate sample names
- message = ''
- for index in range(len(current_samples)-len(request.samples)):
- sample_index = index + len(request.samples)
- sample_name = current_samples[sample_index]['name']
- if not sample_name.strip():
- message = 'Please enter the name of sample number %i' % sample_index
- break
- count = 0
- for i in range(len(current_samples)):
- if sample_name == current_samples[i]['name']:
- count = count + 1
- if count > 1:
- message = "This request has <b>%i</b> samples with the name <b>%s</b>.\nSamples belonging to a request must have unique names." % (count, sample_name)
- break
- if message:
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples = current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, edit_mode=edit_mode,
- status='error', message=message)
- # save all the new/unsaved samples entered by the user
- if edit_mode == 'False':
- for index in range(len(current_samples)-len(request.samples)):
- sample_index = len(request.samples)
- form_values = trans.app.model.FormValues(request.type.sample_form,
- current_samples[sample_index]['field_values'])
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- s = trans.app.model.Sample(current_samples[sample_index]['name'], '',
- request, form_values,
- current_samples[sample_index]['barcode'],
- current_samples[sample_index]['library'],
- current_samples[sample_index]['folder'],
- dataset_files=[])
- trans.sa_session.add( s )
- trans.sa_session.flush()
+
- else:
- status = 'done'
- message = 'Changes made to the sample(s) are saved. '
- for sample_index in range(len(current_samples)):
- sample = request.samples[sample_index]
- sample.name = current_samples[sample_index]['name']
- sample.library = current_samples[sample_index]['library']
- sample.folder = current_samples[sample_index]['folder']
- if request.submitted():
- bc_message = self.__validate_barcode(trans, sample, current_samples[sample_index]['barcode'])
- if bc_message:
- status = 'error'
- message += bc_message
- else:
- if not sample.bar_code:
- # if this is a 'new' (still in its first state) sample
- # change the state to the next
- if sample.current_state().id == request.type.states[0].id:
- event = trans.app.model.SampleEvent(sample,
- request.type.states[1],
- 'Sample added to the system')
- trans.sa_session.add( event )
- trans.sa_session.flush()
- sample.bar_code = current_samples[sample_index]['barcode']
- trans.sa_session.add( sample )
- trans.sa_session.flush()
- form_values = trans.sa_session.query( trans.app.model.FormValues ).get( sample.values.id )
- form_values.content = current_samples[sample_index]['field_values']
- trans.sa_session.add( form_values )
- trans.sa_session.flush()
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='show_request',
- id=trans.security.encode_id(request.id),
- status=status,
- message=message ))
- elif params.get('edit_samples_button', False) == 'Edit samples':
- edit_mode = 'True'
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, libraries=libraries,
- edit_mode=edit_mode)
- elif params.get('cancel_changes_button', False) == 'Cancel':
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='show_request',
- id=trans.security.encode_id(request.id)) )
- else:
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples=current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details, libraries=libraries,
- edit_mode=edit_mode, status=status, message=message)
-
-
- @web.expose
- @web.require_login( "create/submit sequencing requests" )
- def delete_sample(self, trans, **kwd):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- request = trans.sa_session.query( trans.app.model.Request ).get( int( params.get( 'request_id', 0 ) ) )
- current_samples, details, edit_mode, libraries = self.__update_samples( trans, request, **kwd )
- sample_index = int(params.get('sample_id', 0))
- sample_name = current_samples[sample_index]['name']
- s = request.has_sample(sample_name)
- if s:
- trans.sa_session.delete( s.values )
- trans.sa_session.delete( s )
- trans.sa_session.flush()
- del current_samples[sample_index]
- return trans.fill_template( '/admin/requests/show_request.mako',
- request=request,
- request_details=self.request_details(trans, request.id),
- current_samples = current_samples,
- sample_copy=self.__copy_sample(current_samples),
- details=details,
- edit_mode=edit_mode)
- @web.expose
- @web.require_admin
- def request_details(self, trans, id):
- '''
- Shows the request details
- '''
- request = trans.sa_session.query( trans.app.model.Request ).get( id )
- # list of widgets to be rendered on the request form
- request_details = []
- # main details
- request_details.append(dict(label='User',
- value=str(request.user.email),
- helptext=''))
- request_details.append(dict(label='Description',
- value=request.desc,
- helptext=''))
- request_details.append(dict(label='Type',
- value=request.type.name,
- helptext=''))
- request_details.append(dict(label='State',
- value=request.state(),
- helptext=''))
- request_details.append(dict(label='Date created',
- value=request.create_time,
- helptext=''))
- # form fields
- for index, field in enumerate(request.type.request_form.fields):
- if field['required']:
- req = 'Required'
- else:
- req = 'Optional'
- if field['type'] == 'AddressField':
- if request.values.content[index]:
- request_details.append(dict(label=field['label'],
- value=trans.sa_session.query( trans.app.model.UserAddress ).get( int( request.values.content[index] ) ).get_html(),
- helptext=field['helptext']+' ('+req+')'))
- else:
- request_details.append(dict(label=field['label'],
- value=None,
- helptext=field['helptext']+' ('+req+')'))
- else:
- request_details.append(dict(label=field['label'],
- value=request.values.content[index],
- helptext=field['helptext']+' ('+req+')'))
- if request.notify:
- notify = 'Yes'
- else:
- notify = 'No'
- request_details.append(dict(label='Send email notification once the sequencing request is complete',
- value=notify,
- helptext=''))
- return request_details
- def __validate_barcode(self, trans, sample, barcode):
- '''
- This method makes sure that the given barcode about to be assigned to
- the given sample is gobally unique. That is, barcodes must be unique
- across requests in Galaxy LIMS
- '''
- message = ''
- for index in range(len(sample.request.samples)):
- # check for empty bar code
- if not barcode.strip():
- message = 'Please fill the barcode for sample <b>%s</b>.' % sample.name
- break
- # check all the saved bar codes
- all_samples = trans.sa_session.query( trans.app.model.Sample )
- for s in all_samples:
- if barcode == s.bar_code:
- if sample.id == s.id:
- continue
- else:
- message = '''The bar code <b>%s</b> of sample <b>%s</b>
- belongs another sample. The sample bar codes must be
- unique throughout the system''' % \
- (barcode, sample.name)
- break
- if message:
- break
- return message
@web.expose
@web.require_admin
def bar_codes(self, trans, **kwd):
@@ -1410,21 +481,7 @@ class RequestsAdmin( BaseController ):
email_content = "To: %s\nFrom: no-reply(a)nowhere.edu\nSubject: %s\n\n%s" % (request.user.email, subject, body)
mail.write( email_content )
x = mail.close()
- def change_state(self, trans, sample):
- possible_states = sample.request.type.states
- curr_state = sample.current_state()
- states_input = SelectField('select_state')
- for state in possible_states:
- if curr_state.name == state.name:
- states_input.add_option(state.name+' (Current)', state.id, selected=True)
- else:
- states_input.add_option(state.name, state.id)
- widgets = []
- widgets.append(('Select the new state of the sample from the list of possible state(s)',
- states_input))
- widgets.append(('Comments', TextArea('comment')))
- title = 'Change current state'
- return widgets, title
+
@web.expose
@web.require_admin
def save_state(self, trans, **kwd):
@@ -1449,71 +506,14 @@ class RequestsAdmin( BaseController ):
trans.sa_session.add( event )
trans.sa_session.flush()
self.__set_request_state( trans, sample.request )
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='show_events',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin',
+ action='sample_events',
sample_id=sample.id))
- @web.expose
- @web.require_admin
- def show_events(self, trans, **kwd):
- params = util.Params( kwd )
- try:
- sample_id = int(params.get('sample_id', False))
- sample = trans.sa_session.query( trans.app.model.Sample ).get( sample_id )
- except:
- message = "Invalid sample ID"
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message=message,
- **kwd) )
- events_list = []
- all_events = sample.events
- for event in all_events:
- events_list.append((event.state.name, event.state.desc,
- time_ago(event.update_time), event.comment))
- widgets, title = self.change_state(trans, sample)
- return trans.fill_template( '/admin/samples/events.mako',
- events_list=events_list,
- sample=sample, widgets=widgets, title=title)
-
#
# Data transfer from sequencer
#
- @web.expose
- @web.require_admin
- def show_datatx_page( self, trans, **kwd ):
- params = util.Params( kwd )
- message = util.restore_text( params.get( 'message', '' ) )
- status = params.get( 'status', 'done' )
- try:
- sample = trans.sa_session.query( trans.app.model.Sample ).get( trans.security.decode_id( kwd['sample_id'] ) )
- except:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- status='error',
- message="Invalid sample ID",
- **kwd) )
- # check if a library and folder has been set for this sample yet.
- if not sample.library or not sample.folder:
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
- action='list',
- operation='show_request',
- status='error',
- message="Set a data library and folder for <b>%s</b> to transfer dataset(s)." % sample.name,
- id=trans.security.encode_id(sample.request.id) ) )
- if params.get( 'folder_path', '' ):
- folder_path = util.restore_text( params.get( 'folder_path', '' ) )
- else:
- if len(sample.dataset_files):
- folder_path = os.path.dirname(sample.dataset_files[-1]['filepath'][:-1])
- else:
- folder_path = util.restore_text( sample.request.type.datatx_info.get('data_dir', '') )
- if folder_path[-1] != os.sep:
- folder_path += os.sep
- return trans.fill_template( '/admin/requests/get_data.mako',
- sample=sample, dataset_files=sample.dataset_files,
- message=message, status=status, files=[],
- folder_path=folder_path )
+
def __get_files(self, trans, sample, folder_path):
'''
This method retrieves the filenames to be transfer from the remote host.
@@ -1521,7 +521,8 @@ class RequestsAdmin( BaseController ):
datatx_info = sample.request.type.datatx_info
if not datatx_info['host'] or not datatx_info['username'] or not datatx_info['password']:
message = "Error in sequencer login information."
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin' ,
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
status='error',
@@ -1536,7 +537,8 @@ class RequestsAdmin( BaseController ):
timeout=10)
if 'No such file or directory' in output:
message = "No such folder (%s) exists on the sequencer." % folder_path
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin' ,
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
message=message, status='error',
@@ -1574,7 +576,8 @@ class RequestsAdmin( BaseController ):
if params.get( 'start_transfer_button', False ) == 'True':
return self.__start_datatx(trans, sample)
if not folder_path:
- return trans.fill_template( '/admin/requests/get_data.mako',
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller='requests_admin',
sample=sample, files=[],
dataset_files=sample.dataset_files,
folder_path=folder_path )
@@ -1585,7 +588,8 @@ class RequestsAdmin( BaseController ):
files = self.__get_files(trans, sample, folder_path)
if folder_path[-1] != os.sep:
folder_path += os.sep
- return trans.fill_template( '/admin/requests/get_data.mako',
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller='requests_admin',
sample=sample, files=files,
dataset_files=sample.dataset_files,
folder_path=folder_path )
@@ -1596,7 +600,8 @@ class RequestsAdmin( BaseController ):
files = self.__get_files(trans, sample, folder_path)
if folder_path[-1] != os.sep:
folder_path += os.sep
- return trans.fill_template( '/admin/requests/get_data.mako',
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller='requests_admin',
sample=sample, files=files,
dataset_files=sample.dataset_files,
folder_path=folder_path )
@@ -1607,7 +612,8 @@ class RequestsAdmin( BaseController ):
files = self.__get_files(trans, sample, folder_path)
if folder_path[-1] != os.sep:
folder_path += os.sep
- return trans.fill_template( '/admin/requests/get_data.mako',
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller='requests_admin',
sample=sample, files=files,
dataset_files=sample.dataset_files,
folder_path=folder_path )
@@ -1618,7 +624,8 @@ class RequestsAdmin( BaseController ):
del sample.dataset_files[dataset_index]
trans.sa_session.add( sample )
trans.sa_session.flush()
- return trans.fill_template( '/admin/requests/get_data.mako',
+ return trans.fill_template( '/requests/common/get_data.mako',
+ cntrller='requests_admin',
sample=sample, files=files,
dataset_files=sample.dataset_files,
folder_path=folder_path)
@@ -1651,7 +658,8 @@ class RequestsAdmin( BaseController ):
folder_path=folder_path,
open_folder=True))
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin' ,
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
folder_path=folder_path))
@@ -1780,13 +788,15 @@ class RequestsAdmin( BaseController ):
not datatx_info['username'] or \
not datatx_info['password']:
message = "Error in sequencer login information."
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin' ,
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
status='error',
message=message))
self.__send_message(trans, datatx_info, sample)
- return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ return trans.response.send_redirect( web.url_for( controller='requests_common',
+ cntrller='requests_admin' ,
action='show_datatx_page',
sample_id=trans.security.encode_id(sample.id),
folder_path=datatx_info['data_dir']))
1
0
galaxy-dist commit 9289b4d7fa4d: API: Patch from Brad Chapman to prevent deleted items from appearing in library contents listing.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1277904834 14400
# Node ID 9289b4d7fa4d1d1b630c044dfbc102cf870f62e3
# Parent 1d05df35ec27cc606ddc486c83ea090e01a441d8
API: Patch from Brad Chapman to prevent deleted items from appearing in library contents listing.
--- a/lib/galaxy/web/api/contents.py
+++ b/lib/galaxy/web/api/contents.py
@@ -26,7 +26,7 @@ class ContentsController( BaseController
for subfolder in folder.active_folders:
if not admin:
can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder )
- if admin or can_access:
+ if (admin or can_access) and not subfolder.deleted:
subfolder.api_path = folder.api_path + '/' + subfolder.name
subfolder.api_type = 'folder'
rval.append( subfolder )
@@ -34,7 +34,7 @@ class ContentsController( BaseController
for ld in folder.datasets:
if not admin:
can_access = trans.app.security_agent.can_access_dataset( current_user_roles, ld.library_dataset_dataset_association.dataset )
- if admin or can_access:
+ if (admin or can_access) and not ld.deleted:
ld.api_path = folder.api_path + '/' + ld.name
ld.api_type = 'file'
rval.append( ld )
1
0
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User jeremy goecks <jeremy.goecks(a)emory.edu>
# Date 1277866995 14400
# Node ID 1d05df35ec27cc606ddc486c83ea090e01a441d8
# Parent 47411bb09df44719760aac61e4b90de4fd190aad
Include job information when exporting and importing histories to/from files. This enables jobs associated with an imported history to be rerun and hence affords a history's analyses to be reproduced exactly. Jobs also have a new flag, imported, that is set to false by default but is true when a job is created via import. Also refactored export/import code to use custom JSON encoders.
This code is in a very alpha/beta state: it may not work well, at all, or as expected. Complex datasets and/or jobs are likely not yet handled. Use with caution.
Also, due to security issues, history/import and history/export methods are not currently web-accessible. Admins must manually make these methods accessible if they want to use them.
--- a/templates/root/index.mako
+++ b/templates/root/index.mako
@@ -40,9 +40,9 @@
"Show structure": function() {
galaxy_main.location = "${h.url_for( controller='history', action='display_structured' )}";
},
- "Export to File": function() {
- galaxy_main.location = "${h.url_for( controller='history', action='export_archive' )}";
- },
+ ##"Export to File": function() {
+ ## galaxy_main.location = "${h.url_for( controller='history', action='export_archive' )}";
+ ##},
"Delete": function()
{
if ( confirm( "Really delete the current history?" ) )
@@ -50,10 +50,10 @@
galaxy_main.location = "${h.url_for( controller='history', action='delete_current' )}";
}
},
- "Other Actions": null,
- "Import from File": function() {
- galaxy_main.location = "${h.url_for( controller='history', action='import_archive' )}";
- }
+ ##"Other Actions": null,
+ ##"Import from File": function() {
+ ## galaxy_main.location = "${h.url_for( controller='history', action='import_archive' )}";
+ ##}
});
// Init tool options.
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -115,6 +115,7 @@ class Job( object ):
self.job_runner_name = None
self.job_runner_external_id = None
self.post_job_actions = None
+ self.imported = False
def add_parameter( self, name, value ):
self.parameters.append( JobParameter( name, value ) )
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0051_imported_col_for_jobs_table.py
@@ -0,0 +1,48 @@
+"""
+Migration script to add imported column for jobs table.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create and initialize imported column in job table.
+ Jobs_table = Table( "job", metadata, autoload=True )
+ c = Column( "imported", Boolean, default=False, index=True )
+ try:
+ # Create
+ c.create( Jobs_table )
+ assert c is Jobs_table.c.imported
+
+ # Initialize.
+ if migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite':
+ default_false = "0"
+ elif migrate_engine.name == 'postgres':
+ default_false = "false"
+ db_session.execute( "UPDATE job SET imported=%s" % default_false )
+
+ except Exception, e:
+ print "Adding imported column to job table failed: %s" % str( e )
+ log.debug( "Adding imported column to job table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop imported column from job table.
+ Jobs_table = Table( "job", metadata, autoload=True )
+ try:
+ Jobs_table.c.imported.drop()
+ except Exception, e:
+ print "Dropping column imported from job table failed: %s" % str( e )
+ log.debug( "Dropping column imported from job table failed: %s" % str( e ) )
--- a/lib/galaxy/web/controllers/history.py
+++ b/lib/galaxy/web/controllers/history.py
@@ -6,6 +6,7 @@ from galaxy.model.mapping import desc
from galaxy.model.orm import *
from galaxy.util.json import *
from galaxy.util.sanitize_html import sanitize_html
+from galaxy.tools.parameters.basic import UnvalidatedValue
from galaxy.tools.actions import upload_common
from galaxy.tags.tag_handler import GalaxyTagHandler
from sqlalchemy.sql.expression import ClauseElement
@@ -145,7 +146,7 @@ class HistoryAllPublishedGrid( grids.Gri
def apply_query_filter( self, trans, query, **kwargs ):
# A public history is published, has a slug, and is not deleted.
return query.filter( self.model_class.published == True ).filter( self.model_class.slug != None ).filter( self.model_class.deleted == False )
-
+
class HistoryController( BaseController, Sharable, UsesAnnotations, UsesHistory ):
@web.expose
def index( self, trans ):
@@ -443,26 +444,26 @@ class HistoryController( BaseController,
trans.sa_session.flush()
return new_annotation
- @web.expose
def import_archive( self, trans, archived_history=None ):
""" Import a history. """
if archived_history is not None:
- # Import archived history.
try:
history_archive_file = tarfile.open( archived_history.file.name )
-
+
# Security check: make sure that members are relative, not absolute.
for tarinfo in history_archive_file.getmembers():
if tarinfo.name.startswith("/") or tarinfo.name.find("..") != -1:
return trans.show_error_message( 'Error importing history archive: archive file is invalid.' )
-
+
# Unpack archive in temporary directory.
temp_output_dir = tempfile.mkdtemp()
history_archive_file.extractall( path=temp_output_dir )
history_archive_file.close()
-
- # Read history attributes.
+
+ #
+ # Create history.
+ #
history_attr_in = open( '%s/%s' % ( temp_output_dir, 'history_attrs.txt'), 'rb' )
history_attr_str = ''
buffsize = 1048576
@@ -473,31 +474,33 @@ class HistoryController( BaseController,
break
except OverflowError:
pass
+ history_attr_in.close()
history_attrs = from_json_string( history_attr_str )
-
+
# Create history.
new_history = model.History( name='imported from archive: %s' % history_attrs['name'].encode( 'utf-8' ), user=trans.user )
trans.sa_session.add( new_history )
-
+
+ new_history.hid_counter = history_attrs['hid_counter']
+ new_history.genome_build = history_attrs['genome_build']
+ trans.sa_session.flush()
+
# Builds a tag string for a tag, value pair.
def get_tag_str( tag, value ):
if not value:
return tag
else:
return tag + ":" + value
-
+
# Add annotation, tags.
if trans.user:
self.add_item_annotation( trans, new_history, history_attrs[ 'annotation' ] )
for tag, value in history_attrs[ 'tags' ].items():
trans.app.tag_handler.apply_item_tags( trans, trans.user, new_history, get_tag_str( tag, value ) )
-
- # Ignore hid_counter since it artificially increases the hid for all HDAs?
- # new_history.hid_counter = history_attrs['hid_counter']
- new_history.genome_build = history_attrs['genome_build']
- trans.sa_session.flush()
-
- # Read datasets attributes.
+
+ #
+ # Create datasets.
+ #
datasets_attr_in = open( '%s/%s' % ( temp_output_dir, 'datasets_attrs.txt'), 'rb' )
datasets_attr_str = ''
buffsize = 1048576
@@ -508,64 +511,187 @@ class HistoryController( BaseController,
break
except OverflowError:
pass
+ datasets_attr_in.close()
datasets_attrs = from_json_string( datasets_attr_str )
-
- # Create datasets.
+
+ # Create datasets.
for dataset_attrs in datasets_attrs:
metadata = dataset_attrs['metadata']
-
+
# Create dataset and HDA.
- hda = trans.app.model.HistoryDatasetAssociation( name = dataset_attrs['name'].encode( 'utf-8' ),
- extension = dataset_attrs['extension'],
- hid = dataset_attrs['hid'],
- info = dataset_attrs['info'].encode( 'utf-8' ),
- blurb = dataset_attrs['blurb'],
- peek = dataset_attrs['peek'],
- designation = dataset_attrs['designation'],
- visible = dataset_attrs['visible'],
- dbkey = metadata['dbkey'],
- metadata = metadata,
- history = new_history,
- create_dataset = True,
- sa_session = trans.sa_session )
+ hda = model.HistoryDatasetAssociation( name = dataset_attrs['name'].encode( 'utf-8' ),
+ extension = dataset_attrs['extension'],
+ info = dataset_attrs['info'].encode( 'utf-8' ),
+ blurb = dataset_attrs['blurb'],
+ peek = dataset_attrs['peek'],
+ designation = dataset_attrs['designation'],
+ visible = dataset_attrs['visible'],
+ dbkey = metadata['dbkey'],
+ metadata = metadata,
+ history = new_history,
+ create_dataset = True,
+ sa_session = trans.sa_session )
hda.state = hda.states.OK
trans.sa_session.add( hda )
trans.sa_session.flush()
new_history.add_dataset( hda, genome_build = None )
+ hda.hid = dataset_attrs['hid'] # Overwrite default hid set when HDA added to history.
permissions = trans.app.security_agent.history_get_default_permissions( new_history )
trans.app.security_agent.set_all_dataset_permissions( hda.dataset, permissions )
trans.sa_session.flush()
-
+
# Copy dataset data.
temp_dataset_name = '%s/datasets/%s' % ( temp_output_dir, dataset_attrs['file_name'] )
shutil.copyfile( temp_dataset_name, hda.file_name )
-
+
# Set tags, annotations.
if trans.user:
self.add_item_annotation( trans, hda, dataset_attrs[ 'annotation' ] )
for tag, value in dataset_attrs[ 'tags' ].items():
trans.app.tag_handler.apply_item_tags( trans, trans.user, hda, get_tag_str( tag, value ) )
- trans.sa_session.flush()
+ trans.sa_session.flush()
+ #
+ # Create jobs.
+ #
+
+ # Read jobs attributes.
+ jobs_attr_in = open( '%s/%s' % ( temp_output_dir, 'jobs_attrs.txt'), 'rb' )
+ jobs_attr_str = ''
+ buffsize = 1048576
+ try:
+ while True:
+ jobs_attr_str += jobs_attr_in.read( buffsize )
+ if not jobs_attr_str or len( jobs_attr_str ) % buffsize != 0:
+ break
+ except OverflowError:
+ pass
+ jobs_attr_in.close()
+
+ # Decode jobs attributes.
+ def as_hda( obj_dct ):
+ """ Hook to 'decode' an HDA; method uses history and HID to get the HDA represented by
+ the encoded object. This only works because HDAs are created above. """
+ if obj_dct.get( '__HistoryDatasetAssociation__', False ):
+ return trans.sa_session.query( model.HistoryDatasetAssociation ) \
+ .filter_by( history=new_history, hid=obj_dct['hid'] ).first()
+ return obj_dct
+ jobs_attrs = from_json_string( jobs_attr_str, object_hook=as_hda )
+
+ # Create each job.
+ for job_attrs in jobs_attrs:
+ imported_job = model.Job()
+ imported_job.user = trans.user
+ imported_job.session = trans.get_galaxy_session().id
+ imported_job.history = new_history
+ imported_job.tool_id = job_attrs[ 'tool_id' ]
+ imported_job.tool_version = job_attrs[ 'tool_version' ]
+ imported_job.set_state( job_attrs[ 'state' ] )
+ imported_job.imported = True
+ trans.sa_session.add( imported_job )
+ trans.sa_session.flush()
+
+ class HistoryDatasetAssociationIDEncoder( simplejson.JSONEncoder ):
+ """ Custom JSONEncoder for a HistoryDatasetAssociation that encodes an HDA as its ID. """
+ def default( self, obj ):
+ """ Encode an HDA, default encoding for everything else. """
+ if isinstance( obj, model.HistoryDatasetAssociation ):
+ return obj.id
+ return simplejson.JSONEncoder.default( self, obj )
+
+ # Set parameters. May be useful to look at metadata.py for creating parameters.
+ # TODO: there may be a better way to set parameters, e.g.:
+ # for name, value in tool.params_to_strings( incoming, trans.app ).iteritems():
+ # job.add_parameter( name, value )
+ # to make this work, we'd need to flesh out the HDA objects. The code below is
+ # relatively similar.
+ for name, value in job_attrs[ 'params' ].items():
+ # Transform parameter values when necessary.
+ if isinstance( value, model.HistoryDatasetAssociation ):
+ # HDA input: use hid to find input.
+ input_hda = trans.sa_session.query( model.HistoryDatasetAssociation ) \
+ .filter_by( history=new_history, hid=value.hid ).first()
+ value = input_hda.id
+ #print "added parameter %s-->%s to job %i" % ( name, value, imported_job.id )
+ imported_job.add_parameter( name, to_json_string( value, cls=HistoryDatasetAssociationIDEncoder ) )
+
+ # TODO: Connect jobs to input datasets.
+
+ # Connect jobs to output datasets.
+ for output_hid in job_attrs[ 'output_datasets' ]:
+ #print "%s job has output dataset %i" % (imported_job.id, output_hid)
+ output_hda = trans.sa_session.query( model.HistoryDatasetAssociation ) \
+ .filter_by( history=new_history, hid=output_hid ).first()
+ if output_hda:
+ imported_job.add_output_dataset( output_hda.name, output_hda )
+ trans.sa_session.flush()
+
# Cleanup.
if os.path.exists( temp_output_dir ):
shutil.rmtree( temp_output_dir )
-
+
return trans.show_ok_message( message="History '%s' has been imported. " % history_attrs['name'] )
except Exception, e:
return trans.show_error_message( 'Error importing history archive. ' + str( e ) )
-
return trans.show_form(
web.FormBuilder( web.url_for(), "Import a History from an Archive", submit_text="Submit" )
.add_input( "file", "Archived History File", "archived_history", value=None, error=None )
)
- @web.expose
def export_archive( self, trans, id=None ):
""" Export a history. """
+ #
+ # Helper methods/classes.
+ #
+
+ def unicode_wrangler( a_string ):
+ """ Convert strings to unicode in utf-8 format. Method should be used for all user input. """
+ a_string_type = type ( a_string )
+ if a_string_type is str:
+ return unicode( a_string, 'utf-8' )
+ elif a_string_type is unicode:
+ return a_string.encode( 'utf-8' )
+
+ def get_item_tag_dict( item ):
+ """ Create dictionary of an item's tags. """
+ tags = {}
+ for tag in item.tags:
+ tag_user_tname = unicode_wrangler( tag.user_tname )
+ tag_user_value = unicode_wrangler( tag.user_value )
+ tags[ tag_user_tname ] = tag_user_value
+ return tags
+
+ class HistoryDatasetAssociationEncoder( simplejson.JSONEncoder ):
+ """ Custom JSONEncoder for a HistoryDatasetAssociation. """
+ def default( self, obj ):
+ """ Encode an HDA, default encoding for everything else. """
+ if isinstance( obj, model.HistoryDatasetAssociation ):
+ return {
+ "__HistoryDatasetAssociation__" : True,
+ "create_time" : obj.create_time.__str__(),
+ "update_time" : obj.update_time.__str__(),
+ "hid" : obj.hid,
+ "name" : unicode_wrangler( obj.name ),
+ "info" : unicode_wrangler( obj.info ),
+ "blurb" : obj.blurb,
+ "peek" : obj.peek,
+ "extension" : obj.extension,
+ "metadata" : dict( obj.metadata.items() ),
+ "parent_id" : obj.parent_id,
+ "designation" : obj.designation,
+ "deleted" : obj.deleted,
+ "visible" : obj.visible,
+ "file_name" : obj.file_name.split('/')[-1],
+ "annotation" : unicode_wrangler( obj.annotation ),
+ "tags" : get_item_tag_dict( obj ),
+ }
+ return simplejson.JSONEncoder.default( self, obj )
+
+ #
# Get history to export.
+ #
if id:
history = self.get_history( trans, id, check_ownership=False, check_accessible=True )
else:
@@ -577,35 +703,24 @@ class HistoryController( BaseController,
history_export_dir_name = "./database/export"
archive_file_name = '%s/%s.tar.gz' % ( history_export_dir_name, trans.security.encode_id( history.id ) )
+
+ #
+ # Do export.
+ #
+
# TODO: for now, always create archive when exporting; this is for debugging purposes.
if True:
# Condition for only creating an archive when history is newer than archive:
#not os.path.exists ( archive_file_name ) or datetime.utcfromtimestamp( os.path.getmtime( archive_file_name ) ) < history.update_time:
# Create archive and stream back to client.
-
- # Convert strings to unicode in utf-8 format. Method should be used for all user input.
- def unicode_wrangler( a_string ):
- a_string_type = type ( a_string )
- if a_string_type is str:
- return unicode( a_string, 'utf-8' )
- elif a_string_type is unicode:
- return a_string.encode( 'utf-8' )
-
- # Create dictionary of an item's tags.
- def get_item_tag_dict( item ):
- tags = {}
- for tag in item.tags:
- tag_user_tname = unicode_wrangler( tag.user_tname )
- tag_user_value = unicode_wrangler( tag.user_value )
- tags[ tag_user_tname ] = tag_user_value
- return tags
-
try:
# Use temporary directory for temp output files.
temp_output_dir = tempfile.mkdtemp()
-
+
+ #
# Write history attributes to file.
+ #
history_attrs = {
"create_time" : history.create_time.__str__(),
"update_time" : history.update_time.__str__(),
@@ -619,58 +734,103 @@ class HistoryController( BaseController,
history_attrs_out = open( history_attrs_file_name, 'w' )
history_attrs_out.write( to_json_string( history_attrs ) )
history_attrs_out.close()
- new_name = '%s/%s' % ( temp_output_dir, "history_attrs.txt" )
- os.rename( history_attrs_file_name, new_name )
- history_attrs_file_name = new_name
-
+
+ #
# Write datasets' attributes to file.
+ #
datasets = self.get_history_datasets( trans, history )
datasets_attrs = []
for dataset in datasets:
- attribute_dict = {
- "create_time" : dataset.create_time.__str__(),
- "update_time" : dataset.update_time.__str__(),
- "hid" : dataset.hid,
- "name" : unicode_wrangler( dataset.name ),
- "info" : unicode_wrangler( dataset.info ),
- "blurb" : dataset.blurb,
- "peek" : dataset.peek,
- "extension" : dataset.extension,
- "metadata" : dict( dataset.metadata.items() ),
- "parent_id" : dataset.parent_id,
- "designation" : dataset.designation,
- "deleted" : dataset.deleted,
- "visible" : dataset.visible,
- "file_name" : dataset.file_name.split('/')[-1],
- "annotation" : unicode_wrangler( self.get_item_annotation_str( trans, history.user, dataset ) ),
- "tags" : get_item_tag_dict( dataset )
- }
- datasets_attrs.append( attribute_dict )
+ dataset.annotation = self.get_item_annotation_str( trans, history.user, dataset )
+ datasets_attrs.append( dataset )
datasets_attrs_file_name = tempfile.NamedTemporaryFile( dir=temp_output_dir ).name
datasets_attrs_out = open( datasets_attrs_file_name, 'w' )
- datasets_attrs_out.write( to_json_string( datasets_attrs ) )
+ datasets_attrs_out.write( to_json_string( datasets_attrs, cls=HistoryDatasetAssociationEncoder ) )
datasets_attrs_out.close()
- new_name = '%s/%s' % ( temp_output_dir, "datasets_attrs.txt" )
- os.rename( datasets_attrs_file_name, new_name )
- datasets_attrs_file_name = new_name
-
- # Write files to archive: (a) history attributes file; (b) datasets attributes file; and (c) datasets files.
+
+ #
+ # Write jobs attributes file.
+ #
+
+ # Get all jobs associated with HDAs.
+ jobs_dict = {}
+ for hda in datasets:
+ # Get the associated job, if any. If this hda was copied from another,
+ # we need to find the job that created the origial hda
+ job_hda = hda
+ while job_hda.copied_from_history_dataset_association: #should this check library datasets as well?
+ job_hda = job_hda.copied_from_history_dataset_association
+ if not job_hda.creating_job_associations:
+ # No viable HDA found.
+ continue
+
+ # Get the job object.
+ job = None
+ for assoc in job_hda.creating_job_associations:
+ job = assoc.job
+ break
+ if not job:
+ # No viable job.
+ continue
+
+ jobs_dict[ job.id ] = job
+
+ # Get jobs' attributes.
+ jobs_attrs = []
+ for id, job in jobs_dict.items():
+ job_attrs = {}
+ job_attrs[ 'tool_id' ] = job.tool_id
+ job_attrs[ 'tool_version' ] = job.tool_version
+ job_attrs[ 'state' ] = job.state
+
+ # Get the job's parameters
+ try:
+ params_objects = job.get_param_values( trans.app )
+ except:
+ # Could not get job params.
+ continue
+
+ params_dict = {}
+ for name, value in params_objects.items():
+ params_dict[ name ] = value
+ job_attrs[ 'params' ] = params_dict
+
+ # Get input, output datasets.
+ input_datasets = [ assoc.dataset.hid for assoc in job.input_datasets ]
+ job_attrs[ 'input_datasets' ] = input_datasets
+ output_datasets = [ assoc.dataset.hid for assoc in job.output_datasets ]
+ job_attrs[ 'output_datasets' ] = output_datasets
+
+ jobs_attrs.append( job_attrs )
+
+ jobs_attrs_file_name = tempfile.NamedTemporaryFile( dir=temp_output_dir ).name
+ jobs_attrs_out = open( jobs_attrs_file_name, 'w' )
+ jobs_attrs_out.write( to_json_string( jobs_attrs, cls=HistoryDatasetAssociationEncoder ) )
+ jobs_attrs_out.close()
+
+ #
+ # Write archive and include: (a) history attributes file; (b) datasets attributes file;
+ # (c) jobs attributes file; and (d) datasets files.
+ #
history_archive_name = '%s/%s.tar.gz' % ( history_export_dir_name, trans.security.encode_id( history.id ) )
history_archive = tarfile.open( history_archive_name, "w:gz" )
history_archive.add( history_attrs_file_name, arcname="history_attrs.txt" )
history_archive.add( datasets_attrs_file_name, arcname="datasets_attrs.txt" )
+ history_archive.add( jobs_attrs_file_name, arcname="jobs_attrs.txt" )
for i, dataset in enumerate( datasets ) :
- history_archive.add( dataset.file_name, arcname="datasets/%s" % datasets_attrs[i]['file_name'] )
+ history_archive.add( dataset.file_name, arcname="datasets/%s" % dataset.file_name.split('/')[-1] )
history_archive.close()
-
+
# Remove temp directory.
if os.path.exists( temp_output_dir ):
shutil.rmtree( temp_output_dir )
-
+
except Exception, e:
return trans.show_error_message( 'Error creating history archive. ' + str( e ) )
-
+
+ #
# Stream archive.
+ #
if os.path.exists( history_archive_name ):
valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
hname = history.name
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -334,7 +334,8 @@ Job.table = Table( "job", metadata,
Column( "session_id", Integer, ForeignKey( "galaxy_session.id" ), index=True, nullable=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True, nullable=True ),
Column( "job_runner_name", String( 255 ) ),
- Column( "job_runner_external_id", String( 255 ) ) )
+ Column( "job_runner_external_id", String( 255 ) ),
+ Column( "imported", Boolean, default=False, index=True ) )
JobParameter.table = Table( "job_parameter", metadata,
Column( "id", Integer, primary_key=True ),
1
0
galaxy-dist commit 10027d1e6dc3: Switch methods using sendmail to SMTP instead.
by commits-noreply@bitbucket.org 16 Jul '10
by commits-noreply@bitbucket.org 16 Jul '10
16 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1277754926 14400
# Node ID 10027d1e6dc31200319f9d90a4d8233170393f2b
# Parent eea2c040ccb7bd0d2a7c6e5eab8e65f98a163009
Switch methods using sendmail to SMTP instead.
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -4,8 +4,9 @@ Contains the user interface in the Unive
from galaxy.web.base.controller import *
from galaxy.model.orm import *
from galaxy import util
-import logging, os, string, re
+import logging, os, string, re, smtplib, socket
from random import choice
+from email.MIMEText import MIMEText
from galaxy.web.form_builder import *
from galaxy.util.json import from_json_string, to_json_string
from galaxy.web.framework.helpers import iff
@@ -152,10 +153,20 @@ class User( BaseController ):
self.__save_user_info( trans, user, action='create', new_user=True, **kwd )
if subscribe_checked:
# subscribe user to email list
- mail = os.popen( "%s -t" % trans.app.config.sendmail_path, 'w' )
- mail.write( "To: %s\nFrom: %s\nSubject: Join Mailing List\n\nJoin Mailing list." % ( trans.app.config.mailing_join_addr,email ) )
- if mail.close():
- error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
+ if trans.app.config.smtp_server is None:
+ error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance."
+ else:
+ msg = MIMEText( 'Join Mailing list.\n' )
+ to = msg[ 'To' ] = trans.app.config.mailing_join_addr
+ frm = msg[ 'From' ] = email
+ msg[ 'Subject' ] = 'Join Mailing List'
+ try:
+ s = smtplib.SMTP()
+ s.connect( trans.app.config.smtp_server )
+ s.sendmail( frm, [ to ], msg.as_string() )
+ s.close()
+ except:
+ error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed."
if not error and not admin_view:
# The handle_user_login() method has a call to the history_set_default_permissions() method
# (needed when logging in with a history), user needs to have default permissions set before logging in
@@ -594,6 +605,8 @@ class User( BaseController ):
webapp=webapp ) )
@web.expose
def reset_password( self, trans, email=None, webapp='galaxy', **kwd ):
+ if trans.app.config.smtp_server is None:
+ return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact an administrator." )
message = util.restore_text( kwd.get( 'message', '' ) )
status = 'done'
if kwd.get( 'reset_password_button', False ):
@@ -608,20 +621,30 @@ class User( BaseController ):
new_pass = ""
for i in range(15):
new_pass = new_pass + choice(chars)
- mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w')
- mail.write("To: %s\nFrom: no-reply(a)nowhere.edu\nSubject: Galaxy Password Reset\n\nYour password has been reset to \"%s\" (no quotes)." % (email, new_pass) )
- if mail.close():
- message = 'Failed to reset password. If this problem persists, please submit a bug report.'
+ host = trans.request.host.split(':')[0]
+ if host == 'localhost':
+ host = socket.getfqdn()
+ msg = MIMEText( 'Your password on %s has been reset to:\n\n %s\n' % ( host, new_pass ) )
+ to = msg[ 'To' ] = email
+ frm = msg[ 'From' ] = 'galaxy-no-reply@' + host
+ msg[ 'Subject' ] = 'Galaxy Password Reset'
+ try:
+ s = smtplib.SMTP()
+ s.connect( trans.app.config.smtp_server )
+ s.sendmail( frm, [ to ], msg.as_string() )
+ s.close()
+ reset_user.set_password_cleartext( new_pass )
+ trans.sa_session.add( reset_user )
+ trans.sa_session.flush()
+ trans.log_event( "User reset password: %s" % email )
+ message = "Password has been reset and emailed to: %s. <a href='%s'>Click here</a> to return to the login form." % ( email, web.url_for( action='login' ) )
+ except Exception, e:
+ message = 'Failed to reset password: %s' % str( e )
status = 'error'
- reset_user.set_password_cleartext( new_pass )
- trans.sa_session.add( reset_user )
- trans.sa_session.flush()
- trans.log_event( "User reset password: %s" % email )
- message = "Password has been reset and emailed to: %s. <a href='%s'>Click here</a> to return to the login form." % ( email, web.url_for( action='login' ) )
return trans.response.send_redirect( web.url_for( controller='user',
action='reset_password',
message=message,
- status='done' ) )
+ status=status ) )
elif email != None:
message = "The specified user does not exist"
status = 'error'
--- a/templates/user/register.mako
+++ b/templates/user/register.mako
@@ -72,13 +72,15 @@
letters, numbers, and the '-' character.
</div></div>
- <div class="form-row">
- <label>Subscribe to mailing list:</label>
- %if subscribe_checked:
- <% subscribe_check_box.checked = True %>
- %endif
- ${subscribe_check_box.get_html()}
- </div>
+ %if trans.app.config.smtp_server:
+ <div class="form-row">
+ <label>Subscribe to mailing list:</label>
+ %if subscribe_checked:
+ <% subscribe_check_box.checked = True %>
+ %endif
+ ${subscribe_check_box.get_html()}
+ </div>
+ %endif
%if user_info_select:
<div class="form-row"><label>User type</label>
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -4,9 +4,10 @@ from galaxy.model.orm import *
from galaxy.datatypes import sniff
from galaxy import model, util
from galaxy.util.streamball import StreamBall
-import logging, tempfile, zipfile, tarfile, os, sys, subprocess
+import logging, tempfile, zipfile, tarfile, os, sys, subprocess, smtplib, socket
from galaxy.web.form_builder import *
from datetime import datetime, timedelta
+from email.MIMEText import MIMEText
from galaxy.web.controllers.forms import get_all_forms
from sqlalchemy.sql.expression import func, and_
from sqlalchemy.sql import select
@@ -1403,13 +1404,21 @@ class RequestsAdmin( BaseController ):
trans.sa_session.flush()
# now that the request is complete send the email notification to the
# the user
- if request.notify:
- mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w')
- subject = "Galaxy Sample Tracking: '%s' sequencing request in complete." % request.name
- body = "The '%s' sequencing request (type: %s) is now complete. Datasets from all the samples are now available for analysis or download from the respective data libraries in Galaxy." % (request.name, request.type.name)
- email_content = "To: %s\nFrom: no-reply(a)nowhere.edu\nSubject: %s\n\n%s" % (request.user.email, subject, body)
- mail.write( email_content )
- x = mail.close()
+ if request.notify and trans.app.config.smtp_server is not None:
+ host = trans.request.host.split(':')[0]
+ if host == 'localhost':
+ host = socket.getfqdn()
+ msg = MIMEText( "The '%s' sequencing request (type: %s) is now complete. Datasets from all the samples are now available for analysis or download from the respective data libraries in Galaxy." % ( request.name, request.type.name ) )
+ to = msg[ 'To' ] = request.user.email
+ frm = msg[ 'From' ] = 'galaxy-no-reply@' + host
+ msg[ 'Subject' ] = "Galaxy Sample Tracking: '%s' sequencing request in complete." % request.name
+ try:
+ s = smtplib.SMTP()
+ s.connect( trans.app.config.smtp_server )
+ s.sendmail( frm, [ to ], msg.as_string() )
+ s.close()
+ except:
+ pass
def change_state(self, trans, sample):
possible_states = sample.request.type.states
curr_state = sample.current_state()
1
0
galaxy-dist commit 47411bb09df4: Remove the display application definitions for the bx application.
by commits-noreply@bitbucket.org 29 Jun '10
by commits-noreply@bitbucket.org 29 Jun '10
29 Jun '10
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>
404 - Not Found — bitbucket.org
</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Mercurial hosting - we're here to serve." />
<meta name="keywords" content="mercurial,hg,hosting,bitbucket," />
<link rel="stylesheet" type="text/css" href="http://bitbucket-assets.s3.amazonaws.com/css/layout.css" />
<link rel="stylesheet" type="text/css" href="http://bitbucket-assets.s3.amazonaws.com/css/screen.css" />
<link rel="stylesheet" type="text/css" href="http://bitbucket-assets.s3.amazonaws.com/css/print.css" media="print" />
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Bitbucket" />
<link rel="icon" href="http://bitbucket-assets.s3.amazonaws.com/img/logo_new.png" type="image/png"/>
<script type="text/javascript">var MEDIA_URL = "http://bitbucket-assets.s3.amazonaws.com/"</script>
<script type="text/javascript" src="http://bitbucket-assets.s3.amazonaws.com/js/lib/bundle.020510May.js"></script>
<script type="text/javascript">
$(document).ready(function() {
Dropdown.init();
$(".tooltip").tipsy({gravity:'s'});
});
</script>
<noscript>
<style type="text/css">
.dropdown-container-text .dropdown {
position: static !important;
}
</style>
</noscript>
<!--[if lt IE 7]>
<style type="text/css">
body {
behavior: url(http://bitbucket-assets.s3.amazonaws.com/css/csshover.htc);
}
#issues-issue pre {
white-space: normal !important;
}
.changeset-description {
white-space: normal !important;
}
</style>
<script type="text/javascript">
$(document).ready(function(){
$('#header-wrapper').pngFix();
$('#sourcelist').pngFix();
$('.promo-signup-screenshot').pngFix();
});
</script>
<![endif]-->
</head>
<body class="">
<div id="main-wrapper">
<div id="header-wrapper">
<div id="header">
<a href="/"><img src="http://bitbucket-assets.s3.amazonaws.com/img/logo_myriad.png" alt="Bitbucket" id="header-wrapper-logo" /></a>
<div id="header-nav">
<ul class="right">
<li><a href="/">Home</a></li>
<li><a href="/plans"><b>Plans & Signup</b></a></li>
<li><a href="/repo/all">Repositories</a></li>
<li><a href="/news">News</a></li>
<li><a href="/help">Help</a></li>
<li><a href="/account/signin/">Sign in</a></li>
</ul>
</div>
</div>
</div>
<div id="content-wrapper">
<div class="container">
<h2>404 - Not Found</h2>
<p>We're sorry, but we couldn't find the page you were looking for.</p>
<p>You can perhaps find what you're looking for by doing a search in the list of <a href="/repo/all/">public repositories</a>.</p>
<p>If you feel that this is an error on our part, please <a href="mailto:support@bitbucket.org">send us an email</a> with details about the error and what you were doing when it occurred.</p>
<p>-- The Bitbucket team</p>
</div>
<div class="cb"></div>
</div>
<div class="cb footer-placeholder"></div>
</div>
<div id="footer-wrapper">
<div id="footer">
<a href="/site/terms/">TOS</a> | <a href="/site/privacy/">Privacy Policy</a> | <a href="http://blog.bitbucket.org/">Blog</a> | <a href="http://bitbucket.org/jespern/bitbucket/issues/new/">Report Bug</a> | <a href="http://groups.google.com/group/bitbucket-users">Discuss</a> | <a href="http://avantlumiere.com/">© 2008-2010</a>
| We run <small><b>
<a href="http://www.djangoproject.com/">Django 1.2.1</a> /
<a href="http://bitbucket.org/jespern/django-piston/">Piston 0.2.3rc1</a> /
<a href="http://www.selenic.com/mercurial/">Hg 1.3.1</a> /
<a href="http://www.python.org">Python 2.5.2</a> /
r3056| fe02
</b></small>
</div>
</div>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456069-3'], ['_trackPageview']);
var _gaq = _gaq || [];
_gaq.push(['atl._setAccount', 'UA-6032469-33'], ['atl._trackPageview']);
(function() {
var ga = document.createElement('script');
ga.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.google-analytics.com/ga.js';
ga.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(ga);
})();
</script>
</body>
</html>
1
0