lists.galaxyproject.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
List overview
Download
galaxy-dev
August 2009
----- 2024 -----
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
galaxy-dev@lists.galaxyproject.org
12 participants
156 discussions
Start a n
N
ew thread
[hg] galaxy 2646: add autocomplete_tagging.css.tmpl to templates...
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/817c183aa633
changeset: 2646:817c183aa633 user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:38:46 2009 -0400 description: add autocomplete_tagging.css.tmpl to templates list 1 file(s) affected in this change: static/june_2007_style/make_style.py diffs (13 lines): diff -r 6f43113ab087 -r 817c183aa633 static/june_2007_style/make_style.py --- a/static/june_2007_style/make_style.py Fri Aug 28 15:36:41 2009 -0400 +++ b/static/june_2007_style/make_style.py Fri Aug 28 15:38:46 2009 -0400 @@ -27,7 +27,8 @@ ( "history.css.tmpl", "history.css" ), ( "tool_menu.css.tmpl", "tool_menu.css" ), ( "iphone.css.tmpl", "iphone.css" ), - ( "reset.css.tmpl", "reset.css" ) ] + ( "reset.css.tmpl", "reset.css" ), + ( "autocomplete_tagging.css.tmpl", "autocomplete_tagging.css") ] images = [ ( "./gradient.py 9 30 $panel_header_bg_top - $panel_header_bg_bottom 0 0 $panel_header_bg_bottom 1 1", "panel_header_bg.png" ),
1
0
0
0
[hg] galaxy 2647: add tagging to histories
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/77dfb7834a94
changeset: 2647:77dfb7834a94 user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:40:32 2009 -0400 description: add tagging to histories 1 file(s) affected in this change: templates/root/history.mako diffs (118 lines): diff -r 817c183aa633 -r 77dfb7834a94 templates/root/history.mako --- a/templates/root/history.mako Fri Aug 28 15:38:46 2009 -0400 +++ b/templates/root/history.mako Fri Aug 28 15:40:32 2009 -0400 @@ -14,8 +14,8 @@ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Pragma" content="no-cache"> -${h.css( "base", "history" )} -${h.js( "jquery", "json2", "jquery.jstore-all" )} +${h.css( "base", "history", "autocomplete_tagging" )} +${h.js( "jquery", "json2", "jquery.jstore-all", "jquery.autocomplete", "autocomplete_tagging" )} <script type="text/javascript"> $(function() { @@ -83,6 +83,93 @@ %endif %endfor }); + + // + // Set up autocomplete tagger. + // +<% + ## Build string of tag name, values. + tag_names_and_values = list() + for tag in history.tags: + tag_name = tag.user_tname + tag_value = "" + if tag.value is not None: + tag_value = tag.user_value + tag_names_and_values.append("\"" + tag_name + "\" : \"" + tag_value + "\"") +%> + // + // Returns the number of keys (elements) in an array/dictionary. + // + var array_length = function(an_array) + { + if (an_array.length) + return an_array.length; + + var count = 0; + for (element in an_array) + count++; + return count; + }; + + // + // Function get text to display on the toggle link. + // + var get_toggle_link_text = function(tags) + { + var text = ""; + var num_tags = array_length(tags); + if (num_tags != 0) + { + text = num_tags + (num_tags != 1 ? " Tags" : " Tag"); + /* + // Show first N tags; hide the rest. + var max_to_show = 1; + + // Build tag string. + var tag_strs = new Array(); + var count = 0; + for (tag_name in tags) + { + tag_value = tags[tag_name]; + tag_strs[tag_strs.length] = build_tag_str(tag_name, tag_value); + if (++count == max_to_show) + break; + } + tag_str = tag_strs.join(", "); + + // Finalize text. + var num_tags_hiding = num_tags - max_to_show; + text = "Tags: " + tag_str + + (num_tags_hiding != 0 ? " and " + num_tags_hiding + " more" : ""); + */ + } + else + { + // No tags. + text = "Add tags to this history"; + } + return text; + }; + + var options = + { + tags : {${", ".join(tag_names_and_values)}}, + get_toggle_link_text_fn: get_toggle_link_text, + input_size: 15, + tag_click_fn: function(tag) { /* Do nothing. */ }, + <% encoded_history_id = trans.security.encode_id(history.id) %> + ajax_autocomplete_tag_url: "${h.url_for( controller='tag', action='tag_autocomplete_data', id=encoded_history_id, item_type="history" )}", + ajax_add_tag_url: "${h.url_for( controller='tag', action='add_tag_async', id=encoded_history_id, item_type="history" )}", + ajax_delete_tag_url: "${h.url_for( controller='tag', action='remove_tag_async', id=encoded_history_id, item_type="history" )}", + delete_tag_img: "${h.url_for('/static/images/delete_tag_icon_gray.png')}", + delete_tag_img_rollover: "${h.url_for('/static/images/delete_tag_icon_white.png')}", + add_tag_img: "${h.url_for('/static/images/add_icon.png')}", + add_tag_img_rollover: "${h.url_for('/static/images/add_icon_dark.png')}", + }; +% if trans.get_user() is not None: + $("#history-tag-area").autocomplete_tagging(options); +% endif + }); // Functionized so AJAX'd datasets can call them // Get shown/hidden state from cookie @@ -290,6 +377,9 @@ <p></p> %endif +<div id="history-tag-area" style="margin-bottom: 1em"> +</div> + <%namespace file="history_common.mako" import="render_dataset" /> %if not datasets:
1
0
0
0
[hg] galaxy 2639: Added samtools-based tools (sam_to_bam, sam_me...
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/36f438ce1f82
changeset: 2639:36f438ce1f82 user: Kelly Vincent <kpvincent(a)bx.psu.edu> date: Fri Aug 28 15:59:16 2009 -0400 description: Added samtools-based tools (sam_to_bam, sam_merge, sam_pileup) with their supporting files and modified Bam datatype so temp files are properly cleaned up 15 file(s) affected in this change: lib/galaxy/datatypes/images.py test-data/chrM.fa test-data/sam_to_bam_in1.sam test-data/sam_to_bam_in2.sam test-data/sam_to_bam_out1.bam test-data/sam_to_bam_out2.bam tool-data/sam_fa_indices.loc.sample tool_conf.xml.sample tools/samtools/sam_merge.py tools/samtools/sam_merge.xml tools/samtools/sam_merge_code.py tools/samtools/sam_pileup.py tools/samtools/sam_pileup.xml tools/samtools/sam_to_bam.py tools/samtools/sam_to_bam.xml diffs (843 lines): diff -r d261f41a2a03 -r 36f438ce1f82 lib/galaxy/datatypes/images.py --- a/lib/galaxy/datatypes/images.py Fri Aug 28 15:29:53 2009 -0400 +++ b/lib/galaxy/datatypes/images.py Fri Aug 28 15:59:16 2009 -0400 @@ -252,14 +252,17 @@ index_file = dataset.metadata.spec['bam_index'].param.new_file( dataset = dataset ) tmp_dir = tempfile.gettempdir() tmpf1 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf1bai = '%s.bai' % tmpf1.name try: subprocess.check_call(['cd', tmp_dir], shell=True) subprocess.check_call('cp %s %s' % (dataset.file_name, tmpf1.name), shell=True) subprocess.check_call('samtools index %s' % tmpf1.name, shell=True) - subprocess.check_call('cp %s.bai %s' % (tmpf1.name, index_file.file_name), shell=True) + subprocess.check_call('cp %s %s' % (tmpf1bai, index_file.file_name), shell=True) except subprocess.CalledProcessError: sys.stderr.write('There was a problem creating the index for the BAM file\n') tmpf1.close() + if os.path.exists(tmpf1bai): + os.remove(tmpf1bai) dataset.metadata.bam_index = index_file def set_peek( self, dataset ): if not dataset.dataset.purged: diff -r d261f41a2a03 -r 36f438ce1f82 test-data/chrM.fa --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/chrM.fa Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,335 @@ +>chrM +GTTAATGTAGCTTAATAATATAAAGCAAGGCACTGAAAATGCCTAGATGA +GTATTCTTACTCCATAAACACATAGGCTTGGTCCTAGCCTTTTTATTAGT +TATTAATAGAATTACACATGCAAGTATCCGCACCCCAGTGAGAATGCCCT +CTAAATCACGTCTCTACGATTAAAAGGAGCAGGTATCAAGCACACTAGAA +AGTAGCTCATAACACCTTGCTCAGCCACACCCCCACGGGACACAGCAGTG +ATAAAAATTAAGCTATGAACGAAAGTTCGACTAAGTCATATTAAATAAGG +GTTGGTAAATTTCGTGCCAGCCACCGCGGTCATACGATTAACCCAAATTA +ATAAATCTCCGGCGTAAAGCGTGTCAAAGACTAATACCAAAATAAAGTTA +AAACCCAGTTAAGCCGTAAAAAGCTACAACCAAAGTAAAATAGACTACGA +AAGTGACTTTAATACCTCTGACTACACGATAGCTAAGACCCAAACTGGGA +TTAGATACCCCACTATGCTTAGCCCTAAACTAAAATAGCTTACCACAACA +AAGCTATTCGCCAGAGTACTACTAGCAACAGCCTAAAACTCAAAGGACTT +GGCGGTGCTTTACATCCCTCTAGAGGAGCCTGTTCCATAATCGATAAACC +CCGATAAACCCCACCATCCCTTGCTAATTCAGCCTATATACCGCCATCTT +CAGCAAACCCTAAACAAGGTACCGAAGTAAGCACAAATATCCAACATAAA +AACGTTAGGTCAAGGTGTAGCCCATGGGATGGAGAGAAATGGGCTACATT +TTCTACCCTAAGAACAAGAACTTTAACCCGGACGAAAGTCTCCATGAAAC +TGGAGACTAAAGGAGGATTTAGCAGTAAATTAAGAATAGAGAGCTTAATT +GAATCAGGCCATGAAGCGCGCACACACCGCCCGTCACCCTCCTTAAATAT +CACAAATCATAACATAACATAAAACCGTGACCCAAACATATGAAAGGAGA +CAAGTCGTAACAAGGTAAGTATACCGGAAGGTGTACTTGGATAACCAAAG +TGTAGCTTAAACAAAGCATCCAGCTTACACCTAGAAGATTTCACTCAAAA +TGAACACTTTGAACTAAAGCTAGCCCAAACAATACCTAATTCAATTACCC +TTAGTCACTTAACTAAAACATTCACCAAACCATTAAAGTATAGGAGATAG +AAATTTTAACTTGGCGCTATAGAGAAAGTACCGTAAGGGAACGATGAAAG +ATGCATTAAAAGTACTAAACAGCAAAGCTTACCCCTTTTACCTTTTGCAT +AATGATTTAACTAGAATAAACTTAGCAAAGAGAACTTAAGCTAAGCACCC +CGAAACCAGACGAGCTACCTATGAACAGTTACAAATGAACCAACTCATCT +ATGTCGCAAAATAGTGAGAAGATTCGTAGGTAGAGGTGAAAAGCCCAACG +AGCCTGGTGATAGCTGGTTGTCCAGAAACAGAATTTCAGTTCAAATTTAA +ATTTACCTAAAAACTACTCAATTCTAATGTAAATTTAAATTATAGTCTAA +AAAGGTACAGCTTTTTAGATACAGGTTACAACCTTCATTAGAGAGTAAGA +ACAAGATAAACCCATAGTTGGCTTAAAAGCAGCCATCAATTAAGAAAGCG +TTCAAGCTCAACGACACATCTATCTTAATCCCAACAATCAACCCAAACTA +ACTCCTAATCTCATACTGGACTATTCTATCAACACATAGAAGCAATAATG +TTAATATGAGTAACAAGAATTATTTCTCCTTGCATAAGCTTATATCAGAA +CGAATACTCACTGATAGTTAACAACAAGATAGGGATAATCCAAAAACTAA +TCATCTATTTAAACCATTGTTAACCCAACACAGGCATGCATCTATAAGGA +AAGATTAAAAGAAGTAAAAGGAACTCGGCAAACACAAACCCCGCCTGTTT +ACCAAAAACATCACCTCTAGCATTTCCAGTATTAGAGGCACTGCCTGCCC +AGTGACATCTGTTtaaacggccgcggtatcctaaccgtgcaaaggtagca +taatcacttgttccctaaatagggacttgtatgaatggccacacgagggt +tttactgtctcttacttccaatcagtgaaattgaccttcccgtgaagagg +cgggaatgactaaataagacgagaagaccctatggagcttTAATTAACTG +ATTCACAAAAAACAACACACAAACCTTAACCTTCAGGGACAACAAAACTT +TTGATTGAATCAGCAATTTCGGTTGGGGTGACCTCGGAGAACAAAACAAC +CTCCGAGTGATTTAAATCCAGACTAACCAGTCAAAATATATAATCACTTA +TTGATCCAAACCATTGATCAACGGAACAAGTTACCCTAGGGATAACAGCG +CAATCCTATTCCAGAGTCCATATCGACAATTAGGGTTTACGACCTCGATG +TTGGATCAAGACATCCTAATGGTGCAACCGCTATTAAGGGTTCGTTTGTT +CAACGATTAAAGTCTTACGTGATCTGAGTTCAGACCGGAGTAATCCAGGT +CGGTTTCTATCTATTCTATACTTTTCCCAGTACGAAAGGACAAGAAAAGT +AGGGCCCACTTTACAAGAAGCGCCCTCAAACTAATAGATGACATAATCTA +AATCTAACTAATTTATAACTTCTACCGCCCTAGAACAGGGCTCgttaggg +tggcagagcccggaaattgcataaaacttaaacctttacactcagaggtt +caactcctctccctaacaacaTGTTCATAATTAACGTCCTCCTCCTAATT +GTCCCAATCTTGCTCGCCGTAGCATTCCTCACACTAGTTGAACGAAAAGT +CTTAGGCTATATGCAACTTCGCAAAGGACCCAACATCGTAGGCCCCTATG +GCCTACTACAACCTATTGCCGATGCCCTCAAACTATTTATCAAAGAGCCA +CTACAACCACTAACATCATCGACATCCATATTCATCATCGCACCAATCCT +AGCCCTAACCCTGGCCTTAACCATATGAATCCCTCTGCCCATACCATACC +CACTAATCAACATAAACCTAGGAATTCTATTCATACTAGCCATGTCCAGC +CTAGCTGTCTACTCAATCCTTTGATCAGGATGGGCCTCAAACTCAAAATA +CGCCCTAATTGGAGCTCTACGAGCAGTAGCACAAACCATCTCATACGAAG +TAACTCTAGCAATCATCCTACTCTCAGTCCTCCTAATAAGCGGATCATTC +ACATTATCAACACTTATTATTACCCAAGAATACCTCTGATTAATCTTCCC +ATCATGACCCTTAGCCATAATGTGATTCATCTCAACATTAGCCGAAACCA +ACCGAGCTCCATTTGACCTAACAGAAGGAGAATCAGAACTCGTCTCTGGA +TTCAACGTTGAATACGCAGCCGGCCCATTTGCTCTATTCTTCCTAGCAGA +ATACGCAAACATCATCATGATAAACATCTTCACAACAACCCTATTTCTAG +GAGCATTTCACAACCCCTACCTGCCAGAACTCTACTCAATTAATTTCACC +ATTAAAGCTCTCCTTCTAACATGTTCCTTCCTATGAATCCGAGCATCCTA +CCCACGATTCCGATATGACCAACTTATACACCTCCTATGAAAGAACTTCC +TACCACTCACACTAGCCCTCTGCATATGACACGTCTCACTTCCAATCATA +CTATCCAGCATCCCACCACAAACATAGGAAATATGTCTGACAAAAGAGTT +ACTTTGATAGAGTAAAACATAGAGGCTCAAACCCTCTTATTTctagaact +acaggaattgaacctgctcctgagaattcaaaatcctccgtgctaccgaa +ttacaccatgtcctaCAAGTAAGGTCAGCTAAATAAGCTATCGGGCCCAT +ACCCCGAAAATGTTGGATTACACCCTTCCCGTACTAATAAATCCCCTTAT +CTTCACAACTATTCTAATAACAGTTCTTCTAGGAACTATAATCGTTATAA +TAAGCTCACACTGACTAATAATCTGAATCGGATTTGAAATAAATCTACTA +GCCATTATCCCTATCCTAATAAAAAAGTACAATCCCCGAACCATAGAAGC +CTCCACCAAATATTTTCTAACCCAAGCCACCGCATCAATACTCCTCATAA +TAGCGATCATCATTAACCTCATACACTCAGGCCAATGAACAATCACAAAA +GTCTTCAACCCCACAGCGTCCATCATTATAACTTCAGCTCTCGCCATAAA +ACTTGGACTCACACCATTCCACTTCTGAGTACCCGAAGTCACACAGGGCA +TCTCATTAACATCAGGTCTCATCCTACTTACATGACAAAAACTAGCCCCA +ATATCAATCCTATATCAAATCTCACCCTCAATTAACCTAAATATCTTATT +AACTATAGCCGTACTGTCAATCCTAGTAGGAGGCTGAGGCGGTCTCAACC +AAACCCAACTACGAAAAATCATAGCATACTCGTCAATCGCGCATATAGGA +TGAATAACAGCTGTCCTAGTATATAACCCAACACTAACAATACTAAACAT +ATTAATTTACATTATAATAACACTCACAATATTCATACTATTTATCCACA +GCTCCTCTACTACAACACTATCACTCTCCCACACATGAAACAAAATACCT +CTAACCACTACACTAATCTTAATTACCTTACTATCCATAGGAGGCCTCCC +CCCACTATCAGGATTCATACCCAAATGAATAATCATTCAAGAGCTCACCA +AAAATAGCAGCATCATCCTCCCCACACTAATAGCCATTATAGCACTACTC +AACCTCTACTTCTACATACGACTAACCTATTCCACCTCACTGACCATATT +CCCATCCACAAACAACATAAAAATAAAATGACAATTCGAAACCAAACGAA +TTACTCTCTTACCCCCGTTAATTGTTATATCCTCCCTACTCCTCCCCCTA +ACCCCCATACTATCAATTTTGGACTAGGAATTTAGGTTAACATCCCAGAC +CAAGAGCCTTCAAAGCTCTAAGCAAGTGAATCCACTTAATTCCTGCATAC +TAAGGACTGCGAGACTCTATCTCACATCAATTGAACGCAAATCAAACTCT +TTTATTAAGCTAAGCCCTTACTAGATTGGTGGGCTACCATCCCACGAAAT +TTTAGTTAACAGCTAAATACCCTAATCAACTGGCTTCAATCTACTTCTCC +CGCCGCCTAGAAAAAAAGGCGGGAGAAGCCCCGGCAGAAATTGAAGCTGC +TCCTTTGAATTTGCAATTCAATGTGAAAATTCACCACGGGACTTGATAAG +AAGAGGATTCCAACCCCTGTCTTTAGATTTACAGTCTAATGCTTACTCAG +CCATCTTACCTATGTTCATCAACCGCTGACTATTTTCAACTAACCACAAA +GACATCGGCACTCTGTACCTCCTATTCGGCGCTTGAGCTGGAATAGTAGG +AACTGCCCTAAGCCTCCTAATCCGTGCTGAATTAGGCCAACCTGGGACCC +TACTAGGAGATGATCAGATCTACAATGTCATTGTAACCGCCCATGCATTC +GTAATAATTTTCTTTATGGTCATACCCATTATAATCGGAGGATTCGGAAA +CTGATTAGTCCCCCTGATAATTGGAGCACCTGATATAGCTTTCCCCCGAA +TAAACAACATAAGCTTCTGATTACTTCCCCCATCATTCCTACTTCTTCTC +GCTTCCTCAATAATTGAAGCAGGTGCCGGAACAGGCTGAACCGTATATCC +TCCTCTAGCTGGAAATCTGGCGCATGCAGGAGCCTCTGTTGACTTAACCA +TTTTCTCTCTCCACCTAGCTGGGGTGTCCTCGATTTTAGGTGCCATCAAC +TTTATTACCACAATCATTAACATAAAACCACCAGCCCTATCCCAATATCA +AACCCCCCTATTCGTTTGATCTGTCCTTATTACGGCAGTACTCCTTCTCC +TAGCCCTCCCGGTCCTAGCAGCAGGCATTACCATGCTTCTCACAGACCGT +AACCTGAACACTACTTTCTTCGACCCCGCAGGAGGAGGGGATCCAATCCT +TTATCAACACCTATTCTGATTCTTCGGACACCCCGAAGTCTATATTCTTA +TCCTACCAGGCTTCGGTATAATCTCACACATCGTCACATACTACTCAGGT +AAAAAGGAACCTTTTGGCTACATGGGTATAGTGTGAGCTATAATATCCAT +TGGCTTTCTAGGCTTCATCGTATGGGCTCACCACATGTTTACAGTAGGGA +TAGACGTTGACACACGAGCATACTTCACATCAGCTACCATAATCATCGCT +ATCCCTACTGGTGTAAAAGTATTCAGCTGACTAGCCACCCTGCACGGAGG +AAATATCAAATGATCTCCAGCTATACTCTGAGCTCTAGGCTTCATCTTCT +TATTCACAGTAGGAGGTCTAACAGGAATCGTCCTAGCTAACTCATCCCTA +GATATTGTTCTCCACGATACTTATTATGTAGTAGCACATTTCCATTATGT +CCTGTCTATAGGAGCAGTCTTCGCCATTATGGGGGGATTTGTACACTGAT +TCCCTCTATTCTCAGGATACACACTCAACCAAACCTGAGCAAAAATCCAC +TTTACAATTATATTCGTAGGGGTAAATATAACCTTCTTCCCACAACATTT +CCTTGGCCTCTCAGGAATGCCACGACGCTATTCTGATTATCCAGACGCAT +ATACAACATGAAATACCATCTCATCCATAGGATCTTTTATCTCACTTACA +GCAGTGATACTAATAATTTTCATAATTTGAGAAGCGTTCGCATCCAAACG +AGAAGTGTCTACAGTAGAATTAACCTCAACTAATCTGGAATGACTACACG +GATGCCCCCCACCATACCACACATTTGAAGAACCCACCTACGTAAACCTA +AAAtaagaaaggaaggaatcgaaccccctctaactggtttcaagccaata +tcataaccactatgtctttctcCATCAATTGAGGTATTAGTAAAAATTAC +ATGACTTTGTCAAAGTTAAATTATAGGTTAAACCCCTATATACCTCTATG +GCCTACCCCTTCCAACTAGGATTCCAAGACGCAACATCCCCTATTATAGA +AGAACTCCTACACTTCCACGACCACACACTAATAATCGTATTCCTAATTA +GCTCTCTAGTATTATATATTATCTCATCAATACTAACAACTAAATTAACC +CATACCAGCACCATAGATGCTCAAGAAGTAGAGACAATTTGAACGATTTT +ACCAGCCATCATCCTTATTCTAATCGCCCTCCCATCCCTACGAATTCTAT +ATATAATAGATGAAATCAATAATCCGTCCCTCACAGTCAAAACAATAGGC +CACCAATGATACTGAAGCTACGAGTATACCGATTACGAAGACTTGACCTT +TGACTCCTACATGATCCCCACATCAGACCTAAAACCAGGAGAATTACGTC +TTCTAGAAGTCGACAATCGAGTGGTTCTCCCCATAGAAATAACCATCCGA +ATGCTAATTTCATCCGAAGACGTCCTACACTCATGAGCTGTGCCCTCCCT +AGGCCTAAAAACAGACGCTATCCCTGGGCGCCTAAATCAGACAACTCTCG +TGGCCTCTCGACCAGGACTTTACTACGGTCAATGCTCAGAGATCTGCGGA +TCAAACCACAGCTTTATACCAATTGTCCTTGAACTAGTTCCACTGAAACA +CTTCGAAGAATGATCTGCATCAATATTATAAAGTCACTAAGAAGCTATTA +TAGCATTAACCTTTTAAGTTAAAGATTGAGGGTTCAACCCCCTCCCTAGT +GATATGCCACAGTTGGATACATCAACATGATTTATTAATATCGTCTCAAT +AATCCTAACTCTATTTATTGTATTTCAACTAAAAATCTCAAAGCACTCCT +ATCCGACACACCCAGAAGTAAAGACAACCAAAATAACAAAACACTCTGCC +CCTTGAGAATCAAAATGAACGAAAATCTATTCGCCTCTTTCGCTACCCCA +ACAATAGTAGGCCTCCCTATTGTAATTCTGATCATCATATTTCCCAGCAT +CCTATTCCCCTCACCCAACCGACTAATCAACAATCGCCTAATCTCAATTC +AACAATGGCTAGTCCAACTTACATCAAAACAAATAATAGCTATCCATAAC +AGCAAAGGACAAACCTGAACTCTTATACTCATATCACTGATCCTATTCAT +TGGCTCAACAAACTTATTAGGCCTACTACCTCACTCATTTACACCAACAA +CACAACTATCAATAAACCTAGGCATAGCTATTCCCCTATGGGCAGGGACA +GTATTCATAGGCTTTCGTCACAAAACAAAAGCAGCCCTAGCCCACTTTCT +ACCTCAAGGGACGCCCATTTTCCTCATCCCCATACTAGTAATTATCGAGA +CTATCAGCCTATTTATTCAACCTGTAGCCCTAGCCGTGCGGCTAACCGCT +AACATTACCGCCGGACACCTCCTAATACACCTCATCGGAGGGGCAACACT +AGCCCTCATAAGCATCAGCCCCTCAACAGCCCTTATTACGTTTATCATCC +TAATTCTACTAACTATCCTCGAATTCGCAGTAGCTATAATCCAAGCCTAC +GTATTCACTCTCCTGGTAAGCCTTTACTTACACGACAACACCTAATGACC +CACCAAACCCACGCTTACCACATAGTAAACCCCAGCCCATGACCACTTAC +AGGAGCCCTATCAGCCCTCCTGATAACATCAGGACTAGCCATGTGATTTC +ACTTTAACTCAACCTTACTTCTAGCTATAGGGCTATTAACTAACATCCTT +ACCATATATCAATGATGACGAGACATCATCCGAGAAAGCACATTCCAAGG +CCATCACACATCAATCGTTCAAAAGGGACTCCGATATGGCATAATCCTTT +TTATTATCTCAGAAGTCTTCTTCTTCTCTGGCTTCTTCTGAGCCTTTTAC +CACTCAAGCCTAGCCCCCACACCCGAACTAGGCGGCTGCTGACCACCCAC +AGGTATCCACCCCTTAAACCCCCTAGAAGTCCCCTTACTCAACACCTCAG +TGCTCCTAGCATCTGGAGTCTCTATCACCTGAGCCCACCATAGCCTAATA +GAAGGAAACCGTAAAAATATGCTCCAAGGCCTATTCATCACAATTTCACT +AGGCGTATACTTCACCCTTCTCCAAGCCTCAGAATACTATGAAGCCTCAT +TTACTATTTCAGATGGAGTATACGGATCAACATTTTTCGTAGCAACAGGG +TTCCACGGACTACACGTAATTATCGGATCTACCTTCCTCATTGTATGTTT +CCTACGCCAACTAAAATTCCACTTTACATCCAGCCACCACTTCGGATTCG +AAGCAGCCGCTTGATACTGACACTTCGTCGACGTAGTCTGACTATTCTTG +TACGTCTCTATTTATTGATGAGGATCCTATTCTTTTAGTATTGACCAGTA +CAATTGACTTCCAATCAATCAGCTTCGGTATAACCCGAAAAAGAATAATA +AACCTCATACTGACACTCCTCACTAACACATTACTAGCCTCGCTACTCGT +ACTCATCGCATTCTGACTACCACAACTAAACATCTATGCAGAAAAAACCA +GCCCATATGAATGCGGATTTGACCCTATAGGGTCAGCACGCCTCCCCTTC +TCAATAAAATTTTTCTTAGTGGCCATTACATTTCTGCTATTCGACTTAGA +AATTGCCCTCCTATTACCCCTTCCATGAGCATCCCAAACAACTAACCTAA +ACACTATACTTATCATAGCACTAGTCCTAATCTCTCTTCTAGCCATCAGC +CTAGCCTACGAATGAACCCAAAAAGGACTAGAATGAACTGAGTATGGTAA +TTAGTTTAAACCAAAACAAATGATTTCGACTCATTAAACTATGATTAACT +TCATAATTACCAACATGTCACTAGTCCATATTAATATCTTCCTAGCATTC +ACAGTATCCCTCGTAGGCCTACTAATGTACCGATCCCACCTAATATCCTC +ACTCCTATGCCTAGAAGGAATAATACTATCACTATTCGTCATAGCAACCA +TAATAGTCCTAAACACCCACTTCACACTAGCTAGTATAATACCTATCATC +TTACTAGTATTTGCTGCCTGCGAACGAGCTCTAGGATTATCCCTACTAGT +CATAGTCTCCAATACTTATGGAGTAGACCACGTACAAAACCTTAACCTCC +TCCAATGCTAAAAATTATCATTCCCACAATCATACTTATGCCCCTTACAT +GACTATCAAAAAAGAATATAATCTGAATCAACACTACAACCTATAGTCTA +TTAATCAGCCTTATCAGCCTATCCCTCCTAAACCAACCTAGCAACAATAG +CCTAAACTTCTCACTAATATTCTTCTCCGATCCCCTATCAGCCCCACTTC +TGGTGTTGACAACATGACTACTGCCACTAATACTCATAGCCAGCCAACAC +CATCTATCTAAGGAACCACTAATCCGAAAAAAACTCTACATCACCATGCT +AACCATACTTCAAACTTTCCTAATCATGACTTTTACCGCCACAGAACTAA +TCTCCTTCTACATCCTATTTGAAGCCACATTAGTTCCAACACTAATTATC +ATCACCCGCTGAGGCAACCAAACAGAACGCCTGAACGCAGGCCTCTACTT +CCTATTCTACACACTAATAGGTTCCCTCCCACTCTTAGTTGCACTAATCT +CTATCCAAAACCTAACAGGCTCACTAAACTTCCTATTAATTCAATACTGA +AACCAAGCACTACCCGACTCTTGATCCAATATTTTCCTATGACTAGCATG +TATAATAGCATTCATAGTCAAAATACCGGTATATGGTCTTCACCTCTGAC +TCCCAAAAGCCCATGTAGAAGCCCCAATTGCCGGATCCATAGTGCTAGCA +GCCATTCTACTAAAACTAGGAGGCTACGGAATACTACGAATTACAACAAT +ACTAAACCCCCAAACTAGCTTTATAGCCTACCCCTTCCTCATACTATCCC +TGTGAGGAATAATCATAACTAGTTCCATCTGCTTGCGACAAACCGATCTA +AAATCACTTATTGCATACTCCTCTGTCAGCCACATAGCCCTAGTAATCGT +AGCCGTCCTCATCCAAACACCATGAAGTTATATAGGAGCTACAGCCCTAA +TAATCGCTCACGGCCTTACATCATCAATACTATTCTGCCTGGCAAACTCA +AATTACGAACGTACCCATAGCCGAACTATAATCCTAGCCCGCGGGCTTCA +AACACTTCTTCCCCTTATAGCAGCCTGATGACTATTAGCCAGCCTAACCA +ACCTGGCCCTCCCTCCCAGCATTAACCTAATTGGAGAGCTATTCGTAGTA +ATATCATCATTCTCATGATCAAATATTACCATTATCCTAATAGGAGCCAA +TATCACCATCACCGCCCTCTACTCCCTATACATACTAATCACAACACAAC +GAGGGAAATACACACACCATATCAACAGCATTAAACCTTCATTTACACGA +GAAAACGCACTCATGGCCCTCCACATGACTCCCCTACTACTCCTATCACT +TAACCCTAAAATTATCCTAGGCTTTACGTACTGTAAATATAGTTTAACAA +AAACACTAGATTGTGGATCTAGAAACAGAAACTTAATATTTCTTATTTAC +CGAGAAAGTATGCAAGAACTGCTAATTCATGCCCCCATGTCCAACAAACA +TGGCTCTCTCAAACTTTTAAAGGATAGGAGCTATCCGTTGGTCTTAGGAA +CCAAAAAATTGGTGCAACTCCAAATAAAAGTAATCAACATGTTCTCCTCC +CTCATACTAGTTTCACTATTAGTACTAACCCTCCCAATCATATTATCAAT +CTTCAATACCTACAAAAACAGCACGTTCCCGCATCATGTAAAAAACACTA +TCTCATATGCCTTCATTACTAGCCTAATTCCCACTATAATATTTATTCAC +TCTGGACAAGAAACAATTATCTCAAACTGACACTGAATAACCATACAAAC +CCTCAAACTATCCCTAAGCTTCAAACTAGATTACTTCTCAATAATTTTCG +TACCAGTAGCCCTATTCGTAACATGATCTATTATGGAATTCTCCCTATGA +TACATGCACTCAGATCCTTACATTACTCGATTTTTTAAATACTTACTTAC +ATTCCTCATCACTATAATAATTCTAGTCACAGCTAACAACCTTTTCCAAC +TGTTCATCGGATGGGAGGGAGTAGGCATCATGTCATTCTTACTAATCGGA +TGATGATACGGCCGAACAGATGCCAACACCGCGGCCCTTCAAGCAATCCT +TTATAACCGCATCGGGGATATCGGCTTCATCATGGCCATAGCCTGATTCC +TATTCAACACCAACACATGAGACCTCCAACAAATCTTCATACTCGACCCC +AACCTTACCAACCTCCCGCTCCTAGGCCTCCTCCTAGCCGCAACTGGCAA +ATCCGCTCAATTTGGACTCCACCCATGACTTCCTTCAGCCATAGAGGGCC +CTACACCAGTCTCAGCCCTACTCCACTCCAGCACAATAGTTGTAGCAGGC +GTCTTCCTGCTAATCCGCTTCCATCCACTAATAGAAAACAACAAAACAAT +CCAGTCACTTACCCTATGCCTAGGAGCCATCACCACACTATTCACAGCAA +TCTGCGCACTCACTCAAAACGATATCAAAAAAATCATTGCTTTCTCCACC +TCCAGCCAACTAGGCCTGATAATCGTAACCATCGGTATCAATCAACCCTA +CCTAGCATTCCTCCACATTTGCACTCACGCATTCTTCAAAGCTATACTAT +TTATATGTTCCGGATCCATTATCCACAGCCTAAATGACGAGCAAGATATC +CGAAAAATAGGCGGACTATTTAATGCAATACCCTTCACCACCACATCTCT +AATTATTGGCAGCCTTGCACTCACCGGAATTCCTTTCCTCACAGGCTTCT +ACTCCAAAGACCTCATCATCGAAACCGCCAACACATCGTACACCAACGCC +TGAGCCCTACTAATAACTCTCATTGCCACATCCCTCACAGCTGTCTACAG +TACCCGAATCATCTTCTTTGCACTCCTAGGGCAACCCCGCTTCCTCCCTC +TGACCTCAATCAACGAAAATAACCCCTTTCTAATTAACTCCATCAAACGC +CTCTTAATTGGCAGCATTTTTGCCGGATTCTTCATCTCCAACAATATCTA +CCCCACAACCGTCCCAGAAATAACCATACCTACTTACATAAAACTCACCG +CCCTCGCAGTAACCATCCTAGGATTTACACTAGCCCTAGAACTAAGCTTG +ATAACCCATAACTTAAAACTAGAACACTCCACCAACGTATTCAAATTCTC +CAACCTCCTAGGATACTACCCAACAATTATACACCGACTCCCACCGCTCG +CTAACCTATCAATAAGCCAAAAATCAGCATCACTTCTACTAGACTCAATC +TGACTAGAAAACATCCTGCCAAAATCTATCTCCCAGTTCCAAATAAAAAC +CTCGATCCTAATTTCCACCCAAAAAGGACAAATCAAATTATATTTCCTCT +CATTCCTCATCACCCTTACCCTAAGCATACTACTTTTTAATCTCCACGAG +TAACCTCTAAAATTACCAAGACCCCAACAAGCAACGATCAACCAGTCACA +ATCACAACCCAAGCCCCATAACTATACAATGCAGCAGCCCCTATAATTTC +CTCACTAAACGCCCCAGAATCTCCAGTATCATAAATAGCTCAAGCCCCCA +CACCACTAAACTTAAACACTACCCCCACTTCCTCACTCTTCAGAACATAT +AAAACCAACATAACCTCCATCAACAACCCTAAAAGAAATACCCCCATAAC +AGTCGTATTAGACACCCATACCTCAGGATACTGCTCAGTAGCCATAGCCG +TTGTATAACCAAAAACAACCAACATTCCTCCCAAATAAATCAAAAACACC +ATCAACCCCAAAAAGGACCCTCCAAAATTCATAATAATACCACAACCTAC +CCCTCCACTTACAATCAGCACTAAACCCCCATAAATAGGTGAAGGTTTTG +AAGAAAACCCCACAAAACTAACAACAAAAATAACACTCAAAATAAACACA +ATATATGTCATCATTATTCCCACGTGGAATCTAACCACGACCAATGACAT +GAAAAATCATCGTTGTATTTCAACTATAAGAACACCAATGACAAACATCC +GGAAATCTCACCCACTAATTAAAATCATCAATCACTCTTTTATTGACCTA +CCAGCCCCCTCAAACATTTCATCATGATGAAACTTCGGCTCCCTCCTAGG +AATCTGCCTAATCCTCCAAATCTTAACAGGCCTATTCCTAGCCATACACT +ACACATCAGACACGACAACTGCCTTCTCATCCGTCACTCACATCTGCCGA +GACGTTAACTACGGATGAATTATTCGCTACCTCCATGCCAACGGAGCATC +AATATTTTTTATCTGCCTCTTCATTCACGTAGGACGCGGCCTCTACTACG +GCTCTTACACATTCCTAGAGACATGAAACATTGGAATCATCCTACTTTTC +ACAGTTATAGCTACAGCATTCATGGGCTATGTCCTACCATGAGGCCAAAT +ATCCTTTTGAGGAGCAACAGTCATCACGAACCTCCTATCAGCAATTCCCT +ACATCGGTACTACCCTCGTCGAGTGAATCTGAGGTGGATTCTCAGTAGAC +AAAGCCACCCTTACCCGATTTTTTGCTTTCCACTTCATCCTACCCTTCAT +CATCACAGCCCTGGTAGTCGTACATTTACTATTTCTTCACGAAACAGGAT +CTAATAACCCCTCAGGAATCCCATCCGATATGGACAAAATCCCATTCCAC +CCATATTATACAATTAAAGACATCCTAGGACTCCTCCTCCTGATCTTGCT +CCTACTAACTCTAGTATTATTCTCCCCCGACCTCCTAGGAGACCCAGACA +ACTACACCCCAGCTAACCCTCTCAGCACTCCCCCTCATATTAAACCAGAA +TGGTACTTCCTGTTTGCCTACGCCATCCTACGCTCCATTCCCAACAAACT +AGGCGGCGTATTAGCCCTAATCCTCTCCATCCTGATCCTAGCACTCATCC +CCACCCTCCACATATCAAAACAACGAAGCATAATATTCCGGCCTCTCAGC +CAATGCGTATTCTGACTCTTAGTGGCAGACTTACTGACACTAACATGAAT +CGGCGGACAGCCAGTGGAACACCCATACGTAATTATCGGCCAACTGGCCT +CAATCCTCTACTTCTCCCTAATTCTCATTTTTATACCACTCGCAAGCACC +ATCGAAAACAATCTTCTAAAATGAAGAGTCCCTGTAGTATATCGCACATT +ACCCTGGTCTTGTAAACCAGAAAAGGGGGAAAACGTTTCCTCCCAAGGAC +TATCAAGGAAGAAGCTCTAGCTCCACCATCAACACCCAAAGCTGAAATTC +TACTTAAACTATTCCTTGATTTCTTCCCCTAAACGACAACAATTTACCCT +CATGTGCTATGTCAGTATCAGATTATACCCCCACATAACACCATACCCAC +CTGACATGCAATATCTTATGAATGGCCTATGTACGTCGTGCATTAAATTG +TCTGCCCCATGAATAATAAGCATGTACATAATATCATTTATCTTACATAA +GTACATTATATTATTGATCGTGCATACCCCATCCAAGTCAAATCATTTCC +AGTCAACACGCATATCACAGCCCATGTTCCACGAGCTTAATCACCAAGCC +GCGGGAAATCAGCAACCCTCCCAACTACGTGTCCCAATCCTCGCTCCGGG +CCCATCCAAACGTGGGGGTTTCTACAATGAAACTATACCTGGCATCTGGT +TCTTTCTTCAGGGCCATTCCCACCCAACCTCGCCCATTCTTTCCCCTTAA +ATAAGACATCTCGATGGACTAATGACTAATCAGCCCATGCTCACACATAA +CTGTGATTTCATGCATTTGGTATCTTTTTATATTTGGGGATGCTATGACT +CAGCTATGGCCGTCAAAGGCCTCGACGCAGTCAATTAAATTGAAGCTGGA +CTTAAATTGAACGTTATTCCTCCGCATCAGCAACCATAAGGTGTTATTCA +GTCCATGGTAGCGGGACATAGGAAACAAgtgcacctgtgcacctgtgcac +ctgtgcacctgtgcacctgtgcacctgtgcacctgtgcacctgtgcacct +gtgcacctgtgcacctgtgcacctgtgcacctgtgcacctgtgcacctgt +gcacctgtgcacctgtgcacctgtgcacctgtgcacctgtgcacctgtgc +acctgtgcacctgtgcacctgtgcacctgtgcacctgtgcacctgtgcac +ctgtgcacctACCCGCGCAGTAAGCAAGTAATATAGCTTTCTTAATCAAA +CCCCCCCTACCCCCCATTAAACTCCACATATGTACATTCAACACAATCTT +GCCAAACCCCAAAAACAAGACTAAACAATGCACAATACTTCATGAAGCTT +AACCCTCGCATGCCAACCATAATAACTCAACACACCTAACAATCTTAACA +GAACTTTCCCCCCGCCATTAATACCAACATGCTACTTTAATCAATAAAAT +TTCCATAGACAGGCATCCCCCTAGATCTAATTTTCTAAATCTGTCAACCC +TTCTTCCCCC diff -r d261f41a2a03 -r 36f438ce1f82 test-data/sam_to_bam_in1.sam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/sam_to_bam_in1.sam Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,10 @@ +HWI-EAS91_1_30788AAXX:1:1:1513:715 16 chrM 9563 25 36M * 0 0 CTGACTACCACAACTAAACATCTATGCNNAAAAAAC I+-II?IDIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1698:516 16 chrM 2735 25 36M * 0 0 TTTACACTCAGAGGTTCAACTCCTCTCNNTAACAAC I9IIIII5IIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1491:637 16 chrM 10864 25 36M * 0 0 TGTAGAAGCCCCAATTGCCGGATCCATNNTGCTAGC DBAIIIIIIIIIIIFIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1711:249 16 chrM 10617 25 36M * 0 0 ACCAAACAGAACGCCTGAACGCAGGCCNNTACTTCC IIIIIIIIIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1634:211 0 chrM 9350 25 36M * 0 0 GAAGCAGNNGCTTGATACTGACACTTCGTCGACGTA IIIIIII""IIIIIIIIIIIIIIIIIIIIII9IIDF NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1218:141 16 chrM 14062 25 36M * 0 0 ACAAAACTAACAACAAAAATAACACTCNNAATAAAC I+IIII1IIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1398:854 16 chrM 3921 25 36M * 0 0 CACCCTTCCCGTACTAATAAATCCCCTNNTCTTCAC IIIII=AIIIIIIIIIIIIIIBIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1310:991 16 chrM 10002 25 36M * 0 0 CTCCTATGCCTAGAAGGAATAATACTANNACTATTC I:2IEI:IIDIIIIII4IIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1716:413 0 chrM 6040 25 36M * 0 0 GATCCAANNCTTTATCAACACCTATTCTGATTCTTC IIIIIII""IIIIIIIIIIIIIIIIIIIIIIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1630:59 16 chrM 12387 25 36M * 0 0 TCATACTCGACCCCAACCTTACCAACCNNCCGCTCC FIIHII;IIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 diff -r d261f41a2a03 -r 36f438ce1f82 test-data/sam_to_bam_in2.sam --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/sam_to_bam_in2.sam Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,10 @@ +HWI-EAS91_1_30788AAXX:1:1:1095:605 0 chrM 23 25 36M * 0 0 AAGCAAGNNACTGAAAATGCCTAGATGAGTATTCTT IIIIIII""IIIIIIIIIIIIIIIEIIIIIIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1650:1185 0 chrM 14956 25 36M * 0 0 ACCCCAGNNAACCCTCTCAGCACTCCCCCTCATATT IIIIIII""IIIIIIIIIIII6IIIIIIIII5I-II NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:799:192 16 chrM 8421 25 36M * 0 0 CCTGTAGCCCTAGCCGTGCGGCTAACCNNTAACATT II%::I<IIIIIEIII8IIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1082:719 16 chrM 7191 25 36M * 0 0 TAAATTAACCCATACCAGCACCATAGANNCTCAAGA <III0EII3+3I29I>III8AIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1746:1180 16 chrM 12013 25 36M * 0 0 CCTAAGCTTCAAACTAGATTACTTCTCNNTAATTTT IIIIIIIIFIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:606:460 0 chrM 4552 25 36M * 0 0 TTAATTTNNATTATAATAACACTCACAATATTCATA IIIIIII""IIIIIIIIIIIIIIIIII?I6IIIII6 NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1059:362 16 chrM 7348 25 36M * 0 0 GGCCACCAATGATACTGAAGCTACGAGNNTACCGAT II/<)2IIIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1483:1161 16 chrM 15080 25 36M * 0 0 TCCTGATCCTAGCACTCATCCCCACCCNNCACATAT HIIIIIFIIAIHIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1273:600 16 chrM 13855 25 36M * 0 0 GTATTAGACACCCATACCTCAGGATACNNCTCAGTA IIIIIIIIIIIIIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 +HWI-EAS91_1_30788AAXX:1:1:1190:1283 16 chrM 15338 25 36M * 0 0 TATATCGCACATTACCCTGGTCTTGTANNCCAGAAA EIII?-IIIIIAIIIIIIIIIIIIIII""IIIIIII NM:i:1 X1:i:1 MD:Z:7N0N27 diff -r d261f41a2a03 -r 36f438ce1f82 test-data/sam_to_bam_out1.bam Binary file test-data/sam_to_bam_out1.bam has changed diff -r d261f41a2a03 -r 36f438ce1f82 test-data/sam_to_bam_out2.bam Binary file test-data/sam_to_bam_out2.bam has changed diff -r d261f41a2a03 -r 36f438ce1f82 tool-data/sam_fa_indices.loc.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tool-data/sam_fa_indices.loc.sample Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,27 @@ +#This is a sample file distributed with Galaxy that enables tools +#to use a directory of Samtools indexed sequences data files. You will need +#to create these data files and then create a sam_fa_indices.loc file +#similar to this one (store it in this directory ) that points to +#the directories in which those files are stored. The sam_fa_indices.loc +#file has this format (white space characters are TAB characters): +# +#<index> <seq> <location> +# +#So, for example, if you had hg18 indexed stored in +#/depot/data2/galaxy/sam/, +#then the sam_fa_indices.loc entry would look like this: +# +#hg18 /depot/data2/galaxy/sam/hg18.fa +# +#and your /depot/data2/galaxy/sam/ directory +#would contain hg18.fa and hg18.fa.fai files: +# +#-rw-r--r-- 1 james universe 830134 2005-09-13 10:12 hg18.fa +#-rw-r--r-- 1 james universe 527388 2005-09-13 10:12 hg18.fa.fai +# +#Your sam_fa_indices.loc file should include an entry per line for +#each index set you have stored. The file in the path does actually +#exist, but it should never be directly used. Instead, the name serves +#as a prefix for the index file. For example: +# +#hg18 /depot/data2/galaxy/sam/hg18.fa diff -r d261f41a2a03 -r 36f438ce1f82 tool_conf.xml.sample --- a/tool_conf.xml.sample Fri Aug 28 15:29:53 2009 -0400 +++ b/tool_conf.xml.sample Fri Aug 28 15:59:16 2009 -0400 @@ -331,9 +331,13 @@ <tool file="metag_tools/megablast_xml_parser.xml" /> <tool file="metag_tools/blat_wrapper.xml" /> <tool file="metag_tools/mapping_to_ucsc.xml" /> - <tool file="sr_mapping/bwa_wrapper.xml" /> </section> <section name="Tracks" id="tracks"> <tool file="visualization/genetrack.xml" /> </section> + <section name="SAM Tools" id="samtools"> + <tool file="samtools/sam_to_bam.xml" /> + <tool file="samtools/sam_merge.xml" /> + <tool file="samtools/sam_pileup.xml" /> + </section> </toolbox> diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_merge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_merge.py Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,21 @@ +#! /usr/bin/python + +import os, sys + +def stop_err( msg ): + sys.stderr.write( msg ) + sys.exit() + +def __main__(): + infile = sys.argv[1] + outfile = sys.argv[2] + if len( sys.argv ) < 3: + stop_err( 'No files to merge' ) + filenames = sys.argv[3:] + cmd1 = 'samtools merge %s %s %s' % (outfile, infile, ' '.join(filenames)) + try: + os.system(cmd1) + except Exception, eq: + stop_err('Error running SAMtools merge tool\n' + str(eq)) + +if __name__ == "__main__" : __main__() \ No newline at end of file diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_merge.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_merge.xml Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,32 @@ +<tool id="sam_merge" name="Merge BAM Files" version="1.0.0"> + <description>merges BAM files together</description> + <command interpreter="python"> + sam_merge.py + $input1 + $output1 + $input2 + #for $i in $inputs + ${i.input} + #end for + </command> + <inputs> + <param name="input1" label="First file" type="data" format="bam" /> + <param name="input2" label="with file" type="data" format="bam" help="Need to add more files? Use controls below." /> + <repeat name="inputs" title="Input Files"> + <param name="input" label="Add file" type="data" format="bam" /> + </repeat> + </inputs> + <outputs> + <data name="output1" format="bam" /> + </outputs> + <!-- bam files are binary and not sniffable so can't be uploaded without being corrupted, so no tests --> + <help> + +**What it does** + +This tool uses SAMTools_' merge command to merge any number of BAM files together into one BAM file. + +.. _SAMTools:
http://samtools.sourceforge.net/samtools.shtml
+ + </help> +</tool> diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_merge_code.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_merge_code.py Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,35 @@ +import sets +from galaxy.tools.parameters import DataToolParameter + +def validate_input( trans, error_map, param_values, page_param_map ): + dbkeys = sets.Set() + data_param_names = sets.Set() + data_params = 0 + for name, param in page_param_map.iteritems(): + if isinstance( param, DataToolParameter ): + # for each dataset parameter + if param_values.get(name, None) != None: + dbkeys.add( param_values[name].dbkey ) + data_params += 1 + # check meta data +# try: +# param = param_values[name] +# startCol = int( param.metadata.startCol ) +# endCol = int( param.metadata.endCol ) +# chromCol = int( param.metadata.chromCol ) +# if param.metadata.strandCol is not None: +# strandCol = int ( param.metadata.strandCol ) +# else: +# strandCol = 0 +# except: +# error_msg = "The attributes of this dataset are not properly set. " + \ +# "Click the pencil icon in the history item to set the chrom, start, end and strand columns." +# error_map[name] = error_msg + data_param_names.add( name ) + if len( dbkeys ) > 1: + for name in data_param_names: + error_map[name] = "All datasets must belong to same genomic build, " \ + "this dataset is linked to build '%s'" % param_values[name].dbkey + if data_params != len(data_param_names): + for name in data_param_names: + error_map[name] = "A dataset of the appropriate type is required" \ No newline at end of file diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_pileup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_pileup.py Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,89 @@ +#! /usr/bin/python + +""" +Creates a pileup file from a bam file and a reference. + +usage: %prog [options] + -i, --input1=i: bam file + -o, --output1=o: Output pileup + -r, --ref=r: Reference file type + -n, --ownFile=n: User-supplied fasta reference file + -d, --dbkey=d: dbkey of user-supplied file + -x, --indexDir=x: Index directory + -b, --bamIndex=b: BAM index file + +usage: %prog input1 output1 ref_type refFile ownFile dbkey index_dir bam_index +""" + +import os, sys, tempfile +from galaxy import eggs +import pkg_resources; pkg_resources.require( "bx-python" ) +from bx.cookbook import doc_optparse + +def stop_err( msg ): + sys.stderr.write( msg ) + sys.exit() + +def check_seq_file( dbkey, GALAXY_DATA_INDEX_DIR ): + seq_file = "%s/sam_fa_indices.loc" % GALAXY_DATA_INDEX_DIR + seq_path = '' + for line in open( seq_file ): + line = line.rstrip( '\r\n' ) + if line and not line.startswith( "#" ) and line.startswith( 'index' ): + fields = line.split( '\t' ) + if len( fields ) < 3: + continue + if fields[1] == dbkey: + seq_path = fields[2].strip() + break + return seq_path + +def __main__(): + #Parse Command Line + options, args = doc_optparse.parse( __doc__ ) + seq_path = check_seq_file( options.dbkey, options.indexDir ) + tmp_dir = tempfile.gettempdir() + os.chdir(tmp_dir) + tmpf0 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf0bam = '%s.bam' % tmpf0.name + tmpf0bambai = '%s.bam.bai' % tmpf0.name + tmpf1 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf1fai = '%s.fai' % tmpf1.name + cmd1 = None + cmd2 = 'cp %s %s; cp %s %s' % (options.input1, tmpf0bam, options.bamIndex, tmpf0bambai) + cmd3 = 'samtools pileup -f %s %s > %s 2> /dev/null' + if options.ref =='indexed': + full_path = "%s.fai" % seq_path + if not os.path.exists( full_path ): + stop_err( "No sequences are available for '%s', request them by reporting this error." % options.dbkey ) + cmd3 = cmd3 % (seq_path, tmpf0bam, options.output1) + elif options.ref == 'history': + cmd1 = 'cp %s %s; cp %s.fai %s' % (options.ownFile, tmpf1.name, options.ownFile, tmpf1fai) + cmd3 = cmd3 % (tmpf1.name, tmpf0bam, options.output1) + # index reference if necessary + if cmd1: + try: + os.system(cmd1) + except Exception, eq: + stop_err('Error moving reference sequence\n' + str(eq)) + # copy bam index to working directory + try: + os.system(cmd2) + except Exception, eq: + stop_err('Error moving files to temp directory\n' + str(eq)) + # perform pileup command + try: + os.system(cmd3) + except Exception, eq: + stop_err('Error running SAMtools merge tool\n' + str(eq)) + # clean up temp files + tmpf1.close() + tmpf0.close() + if os.path.exists(tmpf0bam): + os.remove(tmpf0bam) + if os.path.exists(tmpf0bambai): + os.remove(tmpf0bambai) + if os.path.exists(tmpf1fai): + os.remove(tmpf0bambai) + +if __name__ == "__main__" : __main__() diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_pileup.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_pileup.xml Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,50 @@ +<tool id="sam_pileup" name="SAM Pileup Format" version="1.0.0"> + <description>generates the pileup format for a provided BAM file</description> + <command interpreter="python"> + sam_pileup.py + --input1=$input1 + --output=$output1 + --ref=$refOrHistory.reference + #if $refOrHistory.reference == "history": + --ownFile=$refOrHistory.ownFile + #else: + --ownFile="None" + #end if + --dbkey=${input1.metadata.dbkey} + --indexDir=${GALAXY_DATA_INDEX_DIR} + --bamIndex=${input1.metadata.bam_index} + </command> + <inputs> + <conditional name="refOrHistory"> + <param name="reference" type="select" label="Will you select a reference genome from your history or use a built-in index?"> + <option value="indexed">Use a built-in index</option> + <option value="history">Use one from the history</option> + </param> + <when value="indexed"> + <param name="input1" type="data" format="bam" label="Select the BAM file to generate the pileup file for"> + <validator type="unspecified_build" /> + <validator type="dataset_metadata_in_file" filename="sam_fa_indices.loc" metadata_name="dbkey" metadata_column="1" message="Sequences are not currently available for the specified build." line_startswith="index" /> + </param> + </when> + <when value="history"> + <param name="input1" type="data" format="sam, bam" label="Select the BAM file to generate the pileup file for" /> + <param name="ownFile" type="data" format="fasta" metadata_name="dbkey" label="Select a reference genome" /> + </when> + </conditional> + </inputs> + <outputs> + <data format="tabular" name="output1" /> + </outputs> + <!-- tests are not possible because bam is a non-sniffable binary format and cannot be uploaded without being corrupted --> + <help> + +**What it does** + +Uses SAMTools_' pileup command to produce a file in the pileup format based on the provided BAM file. + +.. _SAMTools:
http://samtools.sourceforge.net/samtools.shtml
+ + </help> +</tool> + + diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_to_bam.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_to_bam.py Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,85 @@ +#! /usr/bin/python + +""" +Converts SAM data to BAM format. + +usage: %prog [options] + -i, --input1=i: SAM file to be converted + -d, --dbkey=d: dbkey value + -r, --ref_file=r: Reference file if choosing from history + -o, --output1=o: BAM output + -x, --index_dir=x: Index directory + +usage: %prog input_file dbkey ref_list output_file +""" + +import os, sys, tempfile +from galaxy import eggs +import pkg_resources; pkg_resources.require( "bx-python" ) +from bx.cookbook import doc_optparse + +def stop_err( msg ): + sys.stderr.write( "%s\n" % msg ) + sys.exit() + +def check_seq_file( dbkey, GALAXY_DATA_INDEX_DIR ): + seq_file = "%s/sam_fa_indices.loc" % GALAXY_DATA_INDEX_DIR + seq_path = '' + for line in open( seq_file ): + line = line.rstrip( '\r\n' ) + if line and not line.startswith( "#" ) and line.startswith( 'index' ): + fields = line.split( '\t' ) + if len( fields ) < 3: + continue + if fields[1] == dbkey: + seq_path = fields[2].strip() + break + return seq_path + +def __main__(): + #Parse Command Line + options, args = doc_optparse.parse( __doc__ ) + seq_path = check_seq_file( options.dbkey, options.index_dir ) + tmp_dir = tempfile.gettempdir() + os.chdir(tmp_dir) + tmpf1 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf1fai = '%s.fai' % tmpf1.name + tmpf2 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf3 = tempfile.NamedTemporaryFile(dir=tmp_dir) + tmpf3bam = '%s.bam' % tmpf3.name + if options.ref_file == "None": + full_path = "%s.fai" % seq_path + if not os.path.exists( full_path ): + stop_err( "No sequences are available for '%s', request them by reporting this error." % options.dbkey ) + cmd1 = "cp %s %s; cp %s %s" % (seq_path, tmpf1.name, full_path, tmpf1fai) + else: + cmd1 = "cp %s %s; samtools faidx %s 2>/dev/null" % (options.ref_file, tmpf1.name, tmpf1.name) + cmd2 = "samtools view -bt %s -o %s %s 2>/dev/null" % (tmpf1fai, tmpf2.name, options.input1) + cmd3 = "samtools sort %s %s 2>/dev/null" % (tmpf2.name, tmpf3.name) + cmd4 = "cp %s %s" % (tmpf3bam, options.output1) + # either create index based on fa file or copy provided index to temp directory + try: + os.system(cmd1) + except Exception, eq: + stop_err("Error creating the reference list index.\n" + str(eq)) + # create original bam file + try: + os.system(cmd2) + except Exception, eq: + stop_err("Error running view command.\n" + str(eq)) + # sort original bam file to produce sorted output bam file + try: + os.system(cmd3) + os.system(cmd4) + except Exception, eq: + stop_err("Error sorting data and creating output file.\n" + str(eq)) + # cleanup temp files + tmpf1.close() + tmpf2.close() + tmpf3.close() + if os.path.exists(tmpf1fai): + os.remove(tmpf1fai) + if os.path.exists(tmpf3bam): + os.remove(tmpf3bam) + +if __name__=="__main__": __main__() diff -r d261f41a2a03 -r 36f438ce1f82 tools/samtools/sam_to_bam.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/samtools/sam_to_bam.xml Fri Aug 28 15:59:16 2009 -0400 @@ -0,0 +1,59 @@ +<tool id="sam_to_bam" name="SAM-to-BAM" version="1.0.0"> + <description>converts SAM format to BAM format</description> + <command interpreter="python"> + sam_to_bam.py + --input1=$source.input1 + --dbkey=${input1.metadata.dbkey} + #if $source.indexSource == "history": + --ref_file=$ref_file + #else + --ref_file="None" + #end if + --output1=$output1 + --index_dir=${GALAXY_DATA_INDEX_DIR} + </command> + <inputs> + <conditional name="source"> + <param name="indexSource" type="select" label="Choose the source for the reference list"> + <option value="built_in">Built-in</option> + <option value="history">History</option> + </param> + <when value="built_in"> + <param name="input1" type="data" format="sam" label="SAM File to Convert"> + <validator type="unspecified_build" /> + <validator type="dataset_metadata_in_file" filename="sam_fa_indices.loc" metadata_name="dbkey" metadata_column="1" message="Sequences are not currently available for the specified build." line_startswith="index" /> + </param> + </when> + <when value="history"> + <param name="input1" type="data" format="sam" label="SAM File to Convert" /> + <param name="ref_file" type="data" format="fasta" label="Choose the reference file" /> + </when> + </conditional> + </inputs> + <outputs> + <data name="output1" format="bam"/> + </outputs> + <tests> + <test> + <param name="indexSource" value="history" /> + <param name="input1" value="sam_to_bam_in1.sam" ftype="sam" /> + <param name="ref_file" value="chrM.fa" ftype="fasta" /> + <output name="output1" file="sam_to_bam_out1.bam" /> + </test> + <test> + <param name="indexSource" value="built_in" /> + <param name="input1" value="sam_to_bam_in2.sam" ftype="sam" dbkey="chrM" /> + <param name="ref_file" value="chrM.fa" ftype="fasta" /> + <output name="output1" file="sam_to_bam_out2.bam" /> + </test> + </tests> + <help> + +**What it does** + +This tool uses the SAMTools_ toolkit to produce a BAM file based on a sorted input SAM file. + +.. _SAMTools:
http://samtools.sourceforge.net/samtools.shtml
+ + </help> +</tool>
1
0
0
0
[hg] galaxy 2641: web controller to handle tagging (add/remove/a...
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/6b66a5e142ab
changeset: 2641:6b66a5e142ab user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:27:01 2009 -0400 description: web controller to handle tagging (add/remove/autocomplete) 1 file(s) affected in this change: lib/galaxy/web/controllers/tag.py diffs (151 lines): diff -r b85cb0a65f46 -r 6b66a5e142ab lib/galaxy/web/controllers/tag.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/web/controllers/tag.py Fri Aug 28 15:27:01 2009 -0400 @@ -0,0 +1,147 @@ +""" +Tags Controller: handles tagging/untagging of entities and provides autocomplete support. +""" + +from galaxy.web.base.controller import * +from galaxy.tags.tag_handler import * +from sqlalchemy.sql.expression import func, and_ +from sqlalchemy.sql import select + +class TagsController ( BaseController ): + + def __init__(self, app): + BaseController.__init__(self, app) + + # Set up dict for mapping from short-hand to full item class. + self.shorthand_to_item_class_dict = dict() + self.shorthand_to_item_class_dict["history"] = History + self.shorthand_to_item_class_dict["hda"] = HistoryDatasetAssociation + + # Set up tag handler to recognize the following items: History, HistoryDatasetAssociation, ... + self.tag_handler = TagHandler() + self.tag_handler.add_tag_assoc_class(History, HistoryTagAssociation) + self.tag_handler.add_tag_assoc_class(HistoryDatasetAssociation, HistoryDatasetAssociationTagAssociation) + + @web.expose + def add_tag_async( self, trans, id=None, item_type=None, new_tag=None ): + """ Add tag to an item. """ + item = self._get_item(trans, item_type, trans.security.decode_id(id)) + + self._do_security_check(trans, item) + + self.tag_handler.apply_item_tags(trans.sa_session, item, new_tag) + trans.sa_session.flush() + + @web.expose + def remove_tag_async( self, trans, id=None, item_type=None, tag_name=None ): + """ Remove tag from an item. """ + item = self._get_item(trans, item_type, trans.security.decode_id(id)) + + self._do_security_check(trans, item) + + self.tag_handler.remove_item_tag(item, tag_name) + trans.sa_session.flush() + + # Retag an item. All previous tags are deleted and new tags are applied. + @web.expose + def retag_async( self, trans, id=None, item_type=None, new_tags=None ): + """ Apply a new set of tags to an item; previous tags are deleted. """ + item = self._get_item(trans, item_type, trans.security.decode_id(id)) + + self._do_security_check(trans, item) + + tag_handler.delete_item_tags(item) + self.tag_handler.apply_item_tags(trans.sa_session, item, new_tag) + trans.sa_session.flush() + + tag_handler.delete_item_tags(history) + tag_handler.apply_item_tags(trans.sa_session, history, new_tags) + # Flush to complete changes. + trans.sa_session.flush() + + @web.expose + @web.require_login( "get autocomplete data for an item's tags" ) + def tag_autocomplete_data(self, trans, id=None, item_type=None, q=None, limit=None, timestamp=None): + """ Get autocomplete data for an item's tags. """ + item = self._get_item(trans, item_type, trans.security.decode_id(id)) + + self._do_security_check(trans, item) + + # + # Get user's item tags and usage counts. + # + + # Get item-tag association class. + item_tag_assoc_class = self.tag_handler.get_tag_assoc_class(item.__class__) + + # Build select statement. + cols_to_select = [ item_tag_assoc_class.table.c.tag_id, item_tag_assoc_class.table.c.user_tname, item_tag_assoc_class.table.c.user_value, func.count('*') ] + from_obj = item_tag_assoc_class.table.join(item.table).join(Tag) + where_clause = self._get_column_for_filtering_item_by_user_id(item)==trans.get_user().id + order_by = [ func.count("*").desc() ] + ac_for_names = not q.endswith(":") + if ac_for_names: + # Autocomplete for tag names. + where_clause = and_(where_clause, Tag.table.c.name.like(q + "%")) + group_by = item_tag_assoc_class.table.c.tag_id + else: + # Autocomplete for tag values. + tag_name_and_value = q.split(":") + tag_name = tag_name_and_value[0] + tag_value = tag_name_and_value[1] + where_clause = and_(where_clause, Tag.table.c.name==tag_name) + where_clause = and_(where_clause, item_tag_assoc_class.table.c.value.like(tag_value + "%")) + group_by = item_tag_assoc_class.table.c.value + + # Do query and get result set. + query = select(columns=cols_to_select, from_obj=from_obj, + whereclause=where_clause, group_by=group_by, order_by=order_by) + result_set = trans.sa_session.execute(query) + + # Create and return autocomplete data. + if ac_for_names: + # Autocomplete for tag names. + ac_data = "#Header|Your Tags\n" + for row in result_set: + # Exclude tags that are already applied to the history. + if self.tag_handler.item_has_tag(item, row[1]): + continue + # Add tag to autocomplete data. + ac_data += row[1] + "|" + row[1] + "\n" + else: + # Autocomplete for tag values. + ac_data = "#Header|Your Values for '%s'\n" % (tag_name) + for row in result_set: + ac_data += tag_name + ":" + row[2] + "|" + row[2] + "\n" + + return ac_data + + def _get_column_for_filtering_item_by_user_id(self, item): + """ Returns the column to use when filtering by user id. """ + if isinstance(item, History): + return item.table.c.user_id + elif isinstance(item, HistoryDatasetAssociation): + # Use the user_id associated with the HDA's history. + history = item.history + return history.table.c.user_id + + def _get_item(self, trans, item_type, id): + """ Get an item based on type and id. """ + item_class = self.shorthand_to_item_class_dict[item_type] + item = trans.sa_session.query(item_class).filter("id=" + str(id))[0] + return item; + + def _do_security_check(self, trans, item): + """ Do security check on an item. """ + if isinstance(item, History): + history = item; + # Check that the history exists, and is either owned by the current + # user (if logged in) or the current history + assert history is not None + if history.user is None: + assert history == trans.get_history() + else: + assert history.user == trans.user + elif isinstance(item, HistoryDatasetAssociation): + # TODO. + pass
1
0
0
0
[hg] galaxy 2640: Performance improvements in the GalaxyRBACAgen...
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/cc4944a62b66
changeset: 2640:cc4944a62b66 user: Greg Von Kuster <greg(a)bx.psu.edu> date: Fri Aug 28 16:52:58 2009 -0400 description: Performance improvements in the GalaxyRBACAgent for checking access permissions on libraries. Also added information to main config regarding mysql timeouts ( resolves ticket # 132 ). 27 file(s) affected in this change: lib/galaxy/model/__init__.py lib/galaxy/model/mapping.py lib/galaxy/security/__init__.py lib/galaxy/tools/actions/__init__.py lib/galaxy/tools/parameters/basic.py lib/galaxy/web/controllers/admin.py lib/galaxy/web/controllers/dataset.py lib/galaxy/web/controllers/history.py lib/galaxy/web/controllers/library.py lib/galaxy/web/controllers/root.py templates/admin/library/browse_library.mako templates/dataset/edit_attributes.mako templates/library/browse_library.mako templates/library/common.mako templates/library/folder_info.mako templates/library/folder_permissions.mako templates/library/ldda_edit_info.mako templates/library/ldda_info.mako templates/library/library_dataset_info.mako templates/library/library_dataset_permissions.mako templates/library/library_info.mako templates/library/library_permissions.mako templates/mobile/history/detail.mako templates/mobile/manage_library.mako templates/root/history_common.mako test/base/twilltestcase.py universe_wsgi.ini.sample diffs (1463 lines): diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/model/__init__.py Fri Aug 28 16:52:58 2009 -0400 @@ -723,15 +723,19 @@ return None @property def active_components( self ): - return list( self.active_folders ) + list( self.active_datasets ) + return list( self.active_folders ) + list( self.active_library_datasets ) + @property + def active_library_datasets( self ): + # This needs to be a list + return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.deleted ] + @property + def activatable_library_datasets( self ): + # This needs to be a list + return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.dataset.deleted ] @property def active_datasets( self ): # This needs to be a list - return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.deleted ] - @property - def activatable_datasets( self ): - # This needs to be a list - return [ ld for ld in self.datasets if not ld.library_dataset_dataset_association.dataset.deleted ] + return [ ld.library_dataset_dataset_association.dataset for ld in self.datasets if not ld.library_dataset_dataset_association.deleted ] @property #make this a relation def activatable_folders( self ): # This needs to be a list diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/model/mapping.py --- a/lib/galaxy/model/mapping.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/model/mapping.py Fri Aug 28 16:52:58 2009 -0400 @@ -740,7 +740,7 @@ assign_mapper( context, DatasetPermissions, DatasetPermissions.table, properties=dict( dataset=relation( Dataset, backref="actions" ), - role=relation( Role, backref="actions" ) + role=relation( Role, backref="dataset_actions" ) ) ) diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/security/__init__.py --- a/lib/galaxy/security/__init__.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/security/__init__.py Fri Aug 28 16:52:58 2009 -0400 @@ -33,8 +33,10 @@ def get_actions( self ): """Get all permitted actions as a list of Action objects""" return self.permitted_actions.__dict__.values() - def allow_action( self, user, action, **kwd ): + def allow_action( self, user, roles, action, **kwd ): raise 'No valid method of checking action (%s) on %s for user %s.' % ( action, kwd, user ) + def get_item_action( self, action, item ): + raise 'No valid method of retrieving action (%s) for item %s.' % ( action, item ) def guess_derived_permissions_for_datasets( self, datasets = [] ): raise "Unimplemented Method" def associate_components( self, **kwd ): @@ -79,40 +81,48 @@ ( self.model.LibraryFolder, self.model.LibraryFolderPermissions ), ( self.model.LibraryDataset, self.model.LibraryDatasetPermissions ), ( self.model.LibraryDatasetDatasetAssociation, self.model.LibraryDatasetDatasetAssociationPermissions ) ) - def allow_action( self, user, action, **kwd ): + @property + def sa_session( self ): + """ + Returns a SQLAlchemy session -- currently just gets the current + session from the threadlocal session context, but this is provided + to allow migration toward a more SQLAlchemy 0.4 style of use. + """ + return self.model.context.current + def allow_action( self, user, roles, action, **kwd ): if 'dataset' in kwd: - return self.allow_dataset_action( user, action, kwd[ 'dataset' ] ) + return self.allow_dataset_action( user, roles, action, kwd[ 'dataset' ] ) elif 'library_item' in kwd: - return self.allow_library_item_action( user, action, kwd[ 'library_item' ] ) + return self.allow_library_item_action( user, roles, action, kwd[ 'library_item' ] ) raise 'No valid method of checking action (%s) for user %s using kwd %s' % ( action, str( user ), str( kwd ) ) - def allow_dataset_action( self, user, action, dataset ): + def allow_dataset_action( self, user, roles, action, dataset ): """Returns true when user has permission to perform an action""" - if not isinstance( dataset, self.model.Dataset ): - dataset = dataset.dataset if not user: if action == self.permitted_actions.DATASET_ACCESS and action.action not in [ dp.action for dp in dataset.actions ]: - return True # anons only get access, and only if there are no roles required for the access action - # other actions (or if the dataset has roles defined for the access action) fall through to the false below + # anons only get access, and only if there are no roles required for the access action + # Other actions (or if the dataset has roles defined for the access action) fall through + # to the false below + return True elif action.action not in [ dp.action for dp in dataset.actions ]: if action.model == 'restrict': - return True # implicit access to restrict-style actions if the dataset does not have the action - # grant-style actions fall through to the false below + # Implicit access to restrict-style actions if the dataset does not have the action + # Grant style actions fall through to the false below + return True else: - user_role_ids = sorted( [ r.id for r in user.all_roles() ] ) perms = self.get_dataset_permissions( dataset ) if action in perms.keys(): # The filter() returns a list of the dataset's role ids of which the user is not a member, # so an empty list means the user has all of the required roles. - if not filter( lambda x: x not in user_role_ids, [ r.id for r in perms[ action ] ] ): - return True # user has all of the roles required to perform the action - # Fall through to the false because the user is missing at least one required role - return False # default is to reject - def allow_library_item_action( self, user, action, library_item ): + if not filter( lambda x: x not in roles, [ r for r in perms[ action ] ] ): + # User has all of the roles required to perform the action + return True + # The user is missing at least one required role + return False + def allow_library_item_action( self, user, roles, action, library_item ): if user is None: # All permissions are granted, so non-users cannot have permissions return False if action.model == 'grant': - user_role_ids = [ r.id for r in user.all_roles() ] # Check to see if user has access to any of the roles allowed_role_assocs = [] for item_class, permission_class in self.library_item_assocs: @@ -126,11 +136,17 @@ elif permission_class == self.model.LibraryDatasetDatasetAssociationPermissions: allowed_role_assocs = permission_class.filter_by( action=action.action, library_dataset_dataset_association_id=library_item.id ).all() for allowed_role_assoc in allowed_role_assocs: - if allowed_role_assoc.role_id in user_role_ids: + if allowed_role_assoc.role in roles: return True return False else: raise 'Unimplemented model (%s) specified for action (%s)' % ( action.model, action.action ) + def get_item_action( self, action, item ): + # item must be one of: Dataset, Library, LibraryFolder, LibraryDataset, LibraryDatasetDatasetAssociation + for permission in item.actions: + if permission.action == action: + return permission + return None def guess_derived_permissions_for_datasets( self, datasets=[] ): """Returns a dict of { action : [ role, role, ... ] } for the output dataset based upon provided datasets""" perms = {} @@ -260,7 +276,10 @@ if [ assoc for assoc in dataset.history_associations if assoc.history not in user.histories ]: # Don't change permissions on a dataset associated with a history not owned by the user continue - if bypass_manage_permission or self.allow_action( user, self.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=dataset ): + if bypass_manage_permission or self.allow_action( user, + user.all_roles(), + self.permitted_actions.DATASET_MANAGE_PERMISSIONS, + dataset=dataset ): self.set_all_dataset_permissions( dataset, permissions ) def history_get_default_permissions( self, history ): permissions = {} @@ -402,17 +421,18 @@ lp = permission_class( action.action, target_library_item, private_role ) lp.flush() else: - raise 'Invalid class (%s) specified for target_library_item (%s)' % ( target_library_item.__class__, target_library_item.__class__.__name__ ) - def show_library_item( self, user, library_item ): - if self.allow_action( user, self.permitted_actions.LIBRARY_MODIFY, library_item=library_item ) or \ - self.allow_action( user, self.permitted_actions.LIBRARY_MANAGE, library_item=library_item ) or \ - self.allow_action( user, self.permitted_actions.LIBRARY_ADD, library_item=library_item ): + raise 'Invalid class (%s) specified for target_library_item (%s)' % \ + ( target_library_item.__class__, target_library_item.__class__.__name__ ) + def show_library_item( self, user, roles, library_item ): + if self.allow_action( user, roles, self.permitted_actions.LIBRARY_MODIFY, library_item=library_item ) or \ + self.allow_action( user, roles, self.permitted_actions.LIBRARY_MANAGE, library_item=library_item ) or \ + self.allow_action( user, roles, self.permitted_actions.LIBRARY_ADD, library_item=library_item ): return True if isinstance( library_item, self.model.Library ): - return self.show_library_item( user, library_item.root_folder ) + return self.show_library_item( user, roles, library_item.root_folder ) elif isinstance( library_item, self.model.LibraryFolder ): for folder in library_item.folders: - if self.show_library_item( user, folder ): + if self.show_library_item( user, roles, folder ): return True return False def set_entity_user_associations( self, users=[], roles=[], groups=[], delete_existing_assocs=True ): @@ -462,26 +482,30 @@ if 'role' in kwd: return self.model.GroupRoleAssociation.filter_by( role_id = kwd['role'].id, group_id = kwd['group'].id ).first() raise 'No valid method of associating provided components: %s' % kwd - def check_folder_contents( self, user, entry ): + def check_folder_contents( self, user, roles, folder ): """ - Return true if there are any datasets under 'folder' that the - user has access permission on. We do this a lot and it's a - pretty inefficient method, optimizations are welcomed. + Return true if there are any datasets under 'folder' that are public or that the + user has access permission on. """ - if isinstance( entry, self.model.Library ): - return self.check_folder_contents( user, entry.root_folder ) - elif isinstance( entry, self.model.LibraryFolder ): - for library_dataset in entry.active_datasets: - if self.allow_action( user, self.permitted_actions.DATASET_ACCESS, dataset=library_dataset.library_dataset_dataset_association.dataset ): - return True - for folder in entry.active_folders: - if self.check_folder_contents( user, folder ): - return True - return False - elif isinstance( entry, self.model.LibraryDatasetDatasetAssociation ): - return self.allow_action( user, self.permitted_actions.DATASET_ACCESS, dataset=entry.dataset ) - else: - raise 'Passed an illegal object to check_folder_contents: %s' % type( entry ) + action = self.permitted_actions.DATASET_ACCESS.action + lddas = self.sa_session.query( self.model.LibraryDatasetDatasetAssociation ) \ + .join( "library_dataset" ) \ + .filter( self.model.LibraryDataset.folder == folder ) \ + .join( "dataset" ) \ + .options( eagerload_all( "dataset.actions" ) ) \ + .all() + for ldda in lddas: + ldda_access = self.get_item_action( action, ldda.dataset ) + if ldda_access is None: + # Dataset is public + return True + if ldda_access.role in roles: + # The current user has access permission on the dataset + return True + for sub_folder in folder.active_folders: + if self.check_folder_contents( user, roles, sub_folder ): + return True + return False class HostAgent( RBACAgent ): """ diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/tools/actions/__init__.py --- a/lib/galaxy/tools/actions/__init__.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/tools/actions/__init__.py Fri Aug 28 16:52:58 2009 -0400 @@ -47,8 +47,15 @@ assoc.dataset = new_data assoc.flush() data = new_data - # TODO, Nate: Make sure the permitted actions here are appropriate. - if data and not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset=data ): + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + if data and not trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset=data.dataset ): raise "User does not have permission to use a dataset (%s) provided for input." % data.id return data if isinstance( input, DataToolParameter ): @@ -261,10 +268,17 @@ # parameters to the command as a special case. for name, value in tool.params_to_strings( incoming, trans.app ).iteritems(): job.add_parameter( name, value ) + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None for name, dataset in inp_data.iteritems(): if dataset: - # TODO, Nate: Make sure the permitted actions here are appropriate. - if not trans.app.security_agent.allow_action( trans.user, dataset.permitted_actions.DATASET_ACCESS, dataset=dataset ): + if not trans.app.security_agent.allow_action( user, + roles, + dataset.permitted_actions.DATASET_ACCESS, + dataset=dataset.dataset ): raise "User does not have permission to use a dataset (%s) provided for input." % data.id job.add_input_dataset( name, dataset ) else: diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/tools/parameters/basic.py --- a/lib/galaxy/tools/parameters/basic.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/tools/parameters/basic.py Fri Aug 28 16:52:58 2009 -0400 @@ -1137,6 +1137,11 @@ field = form_builder.SelectField( self.name, self.multiple, None, self.refresh_on_change, refresh_on_change_values = self.refresh_on_change_values ) # CRUCIAL: the dataset_collector function needs to be local to DataToolParameter.get_html_field() def dataset_collector( hdas, parent_hid ): + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None for i, hda in enumerate( hdas ): if len( hda.name ) > 30: hda_name = '%s..%s' % ( hda.name[:17], hda.name[-11:] ) @@ -1148,12 +1153,18 @@ hid = str( hda.hid ) if not hda.dataset.state in [galaxy.model.Dataset.states.ERROR, galaxy.model.Dataset.states.DISCARDED] and \ hda.visible and \ - trans.app.security_agent.allow_action( trans.user, hda.permitted_actions.DATASET_ACCESS, dataset=hda ): + trans.app.security_agent.allow_action( user, + roles, + hda.permitted_actions.DATASET_ACCESS, + dataset=hda.dataset ): # If we are sending data to an external application, then we need to make sure there are no roles # associated with the dataset that restrict it's access from "public". We determine this by sending # None as the user to the allow_action method. if self.tool and self.tool.tool_type == 'data_destination': - if not trans.app.security_agent.allow_action( None, hda.permitted_actions.DATASET_ACCESS, dataset=hda ): + if not trans.app.security_agent.allow_action( None, + None, + hda.permitted_actions.DATASET_ACCESS, + dataset=hda.dataset ): continue if self.options and hda.get_dbkey() != filter_value: continue @@ -1165,7 +1176,10 @@ if target_ext: if converted_dataset: hda = converted_dataset - if not trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=hda.dataset ): + if not trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.DATASET_ACCESS, + dataset=hda.dataset ): continue selected = ( value and ( hda in value ) ) field.add_option( "%s: (as %s) %s" % ( hid, target_ext, hda_name ), hda.id, selected ) diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/web/controllers/admin.py --- a/lib/galaxy/web/controllers/admin.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/web/controllers/admin.py Fri Aug 28 16:52:58 2009 -0400 @@ -269,7 +269,7 @@ gra.delete() gra.flush() # Delete DatasetPermissionss - for dp in role.actions: + for dp in role.dataset_actions: dp.delete() dp.flush() msg = "The following have been purged from the database for role '%s': " % role.name @@ -997,16 +997,8 @@ msg=msg, messagetype=messagetype ) elif action == 'delete': - def delete_folder( folder ): - folder.refresh() - for subfolder in folder.active_folders: - delete_folder( subfolder ) - for ldda in folder.active_datasets: - ldda.deleted = True - ldda.flush() - folder.deleted = True - folder.flush() - delete_folder( folder ) + folder.deleted = True + folder.flush() msg = "Folder '%s' and all of its contents have been marked deleted" % folder.name return trans.response.send_redirect( web.url_for( action='browse_library', id=library_id, diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/web/controllers/dataset.py --- a/lib/galaxy/web/controllers/dataset.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/web/controllers/dataset.py Fri Aug 28 16:52:58 2009 -0400 @@ -108,7 +108,15 @@ data = trans.app.model.HistoryDatasetAssociation.get( dataset_id ) if not data: raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid reference dataset id: %s." % str( dataset_id ) ) - if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ): + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + if trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset=data.dataset ): if data.state == trans.model.Dataset.states.UPLOAD: return trans.show_error_message( "Please wait until this dataset finishes uploading before attempting to view it." ) if filename is None or filename.lower() == "index": @@ -142,9 +150,17 @@ if 'display_url' not in kwd or 'redirect_url' not in kwd: return trans.show_error_message( 'Invalid parameters specified for "display at" link, please contact a Galaxy administrator' ) redirect_url = kwd['redirect_url'] % urllib.quote_plus( kwd['display_url'] ) - if trans.app.security_agent.allow_action( None, data.permitted_actions.DATASET_ACCESS, dataset = data ): + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + if trans.app.security_agent.allow_action( None, None, data.permitted_actions.DATASET_ACCESS, dataset=data.dataset ): return trans.response.send_redirect( redirect_url ) # anon access already permitted by rbac - if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ): + if trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset=data.dataset ): trans.app.host_security_agent.set_dataset_permissions( data, trans.user, site ) return trans.response.send_redirect( redirect_url ) else: diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/web/controllers/history.py --- a/lib/galaxy/web/controllers/history.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/web/controllers/history.py Fri Aug 28 16:52:58 2009 -0400 @@ -411,6 +411,7 @@ err_msg=err_msg, share_button=True ) ) user = trans.get_user() + user_roles = user.all_roles() histories, send_to_users, send_to_err = self._get_histories_and_users( trans, user, id, email ) send_to_err = '' # The user has made a choice, so dictionaries will be built for sharing @@ -442,13 +443,15 @@ for hda in history.activatable_datasets: # If the current dataset is not public, we may need to perform an action on it to # make it accessible by the other user. - if not trans.app.security_agent.allow_action( send_to_user, + if not trans.app.security_agent.allow_action( send_to_user, + send_to_user.all_roles(), trans.app.security_agent.permitted_actions.DATASET_ACCESS, - dataset=hda ): + dataset=hda.dataset ): # The user with which we are sharing the history does not have access permission on the current dataset - if trans.app.security_agent.allow_action( user, + if trans.app.security_agent.allow_action( user, + user_roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, - dataset=hda ) and not hda.dataset.library_associations: + dataset=hda.dataset ) and not hda.dataset.library_associations: # The current user has authority to change permissions on the current dataset because # they have permission to manage permissions on the dataset and the dataset is not associated # with a library. @@ -525,6 +528,7 @@ cannot_change = {} no_change_needed = {} unique_no_change_needed = {} + user_roles = user.all_roles() for history in histories: for send_to_user in send_to_users: # Make sure the current history has not already been shared with the current send_to_user @@ -552,13 +556,15 @@ no_change_needed[ send_to_user ][ history ] = [ hda ] else: no_change_needed[ send_to_user ][ history ].append( hda ) - elif not trans.app.security_agent.allow_action( send_to_user, + elif not trans.app.security_agent.allow_action( send_to_user, + send_to_user.all_roles(), trans.app.security_agent.permitted_actions.DATASET_ACCESS, - dataset=hda ): + dataset=hda.dataset ): # The user with which we are sharing the history does not have access permission on the current dataset - if trans.app.security_agent.allow_action( user, + if trans.app.security_agent.allow_action( user, + user_roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, - dataset=hda ) and not hda.dataset.library_associations: + dataset=hda.dataset ) and not hda.dataset.library_associations: # The current user has authority to change permissions on the current dataset because # they have permission to manage permissions on the dataset and the dataset is not associated # with a library. diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/web/controllers/library.py --- a/lib/galaxy/web/controllers/library.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/web/controllers/library.py Fri Aug 28 16:52:58 2009 -0400 @@ -62,14 +62,29 @@ params = util.Params( kwd ) msg = util.restore_text( params.get( 'msg', '' ) ) messagetype = params.get( 'messagetype', 'done' ) - all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ).order_by( trans.app.model.Library.name ).all() + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted==False ) \ + .order_by( trans.app.model.Library.name ).all() authorized_libraries = [] for library in all_libraries: - if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ) or \ - trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ) or \ - trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ) or \ - trans.app.security_agent.check_folder_contents( trans.user, library ) or \ - trans.app.security_agent.show_library_item( trans.user, library ): + if trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.LIBRARY_ADD, + library_item=library ) or \ + trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, + library_item=library ) or \ + trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, + library_item=library ) or \ + trans.app.security_agent.check_folder_contents( user, roles, library.root_folder ) or \ + trans.app.security_agent.show_library_item( user, roles, library ): authorized_libraries.append( library ) return trans.fill_template( '/library/browse_libraries.mako', libraries=authorized_libraries, @@ -264,9 +279,15 @@ msg=util.sanitize_text( msg ), messagetype='error' ) ) seen = [] + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None for id in ldda_ids: ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( id ) - if not ldda or not trans.app.security_agent.allow_action( trans.user, + if not ldda or not trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset = ldda.dataset ): continue @@ -363,9 +384,15 @@ id=library_id, msg=util.sanitize_text( msg ), messagetype='error' ) ) + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None if action == 'information': if params.get( 'edit_attributes_button', False ): - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library_dataset ): if params.get( 'edit_attributes_button', False ): @@ -391,7 +418,8 @@ messagetype=messagetype ) elif action == 'permissions': if params.get( 'update_roles_button', False ): - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library_dataset ): # The user clicked the Save button on the 'Associate With Roles' form @@ -436,6 +464,11 @@ last_used_build = replace_dataset.library_dataset_dataset_association.dbkey else: replace_dataset = None + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None # Let's not overwrite the imported datatypes module with the variable datatypes? # The built-in 'id' is overwritten in lots of places as well ldatatypes = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ] @@ -479,10 +512,12 @@ if action == 'permissions': if params.get( 'update_roles_button', False ): # The user clicked the Save button on the 'Associate With Roles' form - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda ) and \ - trans.app.security_agent.allow_action( trans.user, + trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ): permissions = {} @@ -523,7 +558,8 @@ elif action == 'edit_info': if params.get( 'change', False ): # The user clicked the Save button on the 'Change data type' form - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda ): if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( params.datatype ).allow_datatype_change: @@ -546,7 +582,8 @@ messagetype=messagetype ) elif params.get( 'save', False ): # The user clicked the Save button on the 'Edit Attributes' form - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda ): old_name = ldda.name @@ -587,7 +624,8 @@ messagetype=messagetype ) elif params.get( 'detect', False ): # The user clicked the Auto-detect button on the 'Edit Attributes' form - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda ): for name, spec in ldda.datatype.metadata_spec.items(): @@ -611,7 +649,8 @@ msg=msg, messagetype=messagetype ) elif params.get( 'delete', False ): - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): ldda.deleted = True @@ -628,7 +667,8 @@ widgets=widgets, msg=msg, messagetype=messagetype ) - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda ): ldda.datatype.before_edit( ldda ) @@ -668,10 +708,12 @@ messagetype='error' ) ) if action == 'permissions': if params.get( 'update_roles_button', False ): - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda ) and \ - trans.app.security_agent.allow_action( trans.user, + trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ): permissions = {} @@ -704,10 +746,12 @@ library_id=library_id, msg=msg, messagetype=messagetype ) - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda ) and \ - trans.app.security_agent.allow_action( trans.user, + trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ): # Ensure that the permissions across all library items are identical, otherwise we can't update them together. @@ -741,10 +785,12 @@ library_id=library_id, msg=msg, messagetype=messagetype ) - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=folder ) or \ - ( replace_dataset and trans.app.security_agent.allow_action( trans.user, + ( replace_dataset and trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=replace_dataset ) ): if params.get( 'new_dataset_button', False ): @@ -769,7 +815,8 @@ # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need # to check one of them to see if the current user can manage permissions on them. check_ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id_list[0] ) - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=check_ldda ): if replace_dataset: @@ -892,7 +939,13 @@ # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need # to check one of them to see if the current user can manage permissions on them. check_ldda = trans.app.model.LibraryDatasetDatasetAssociation.get( ldda_id_list[0] ) - if trans.app.security_agent.allow_action( trans.user, + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=check_ldda ): if replace_dataset: @@ -957,6 +1010,11 @@ id=library_id, msg=util.sanitize_text( msg ), messagetype='error' ) ) + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None if action == 'new': if params.new == 'submitted': new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ), @@ -994,7 +1052,8 @@ else: widgets = [] if params.get( 'rename_folder_button', False ): - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): old_name = folder.name @@ -1037,7 +1096,8 @@ elif action == 'permissions': if params.get( 'update_roles_button', False ): # The user clicked the Save button on the 'Associate With Roles' form - if trans.app.security_agent.allow_action( trans.user, + if trans.app.security_agent.allow_action( user, + roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=folder ): permissions = {} @@ -1162,12 +1222,24 @@ msg=util.sanitize_text( msg ), messagetype='done' ) ) - -def get_authorized_libs(trans, user): - all_libraries = trans.app.model.Library.filter(trans.app.model.Library.table.c.deleted == False).order_by(trans.app.model.Library.name).all() +def get_authorized_libs( trans, user ): + # TODO: this is a mis-named function - the name should reflect the authorization policy + # If user is not authenticated, this method should not even be called. Also, it looks + # like all that is using this is the new request stuff, so it should be placed there. + if not user: + return [] + roles = user.all_roles() + all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted == False ) \ + .order_by( trans.app.model.Library.name ).all() authorized_libraries = [] for library in all_libraries: - if trans.app.security_agent.allow_action(user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library) \ - or trans.app.security_agent.allow_action(user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library): - authorized_libraries.append(library) - return authorized_libraries \ No newline at end of file + if trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.LIBRARY_ADD, + library_item=library ) \ + or trans.app.security_agent.allow_action( user, + roles, + trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, + library_item=library ): + authorized_libraries.append( library ) + return authorized_libraries diff -r 36f438ce1f82 -r cc4944a62b66 lib/galaxy/web/controllers/root.py --- a/lib/galaxy/web/controllers/root.py Fri Aug 28 15:59:16 2009 -0400 +++ b/lib/galaxy/web/controllers/root.py Fri Aug 28 16:52:58 2009 -0400 @@ -152,7 +152,15 @@ except: return "Dataset id '%s' is invalid" %str( id ) if data: - if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ): + user = trans.user + if user: + roles = user.all_roles + else: + roles = None + if trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset = data.dataset ): mime = trans.app.datatypes_registry.get_mimetype_by_extension( data.extension.lower() ) trans.response.set_content_type(mime) if tofile: @@ -184,7 +192,15 @@ if data: child = data.get_child_by_designation( designation ) if child: - if trans.app.security_agent.allow_action( trans.user, child.permitted_actions.DATASET_ACCESS, dataset = child ): + user = trans.user + if user: + roles = user.all_roles + else: + roles = None + if trans.app.security_agent.allow_action( user, + roles, + child.permitted_actions.DATASET_ACCESS, + dataset = child ): return self.display( trans, id=child.id, tofile=tofile, toext=toext ) else: return "You are not privileged to access this dataset." @@ -200,11 +216,21 @@ if 'authz_method' in kwd: authz_method = kwd['authz_method'] if data: - if authz_method == 'rbac' and trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data ): + user = trans.user + if user: + roles = user.all_roles + else: + roles = None + if authz_method == 'rbac' and trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset = data ): trans.response.set_content_type( data.get_mime() ) trans.log_event( "Formatted dataset id %s for display at %s" % ( str( id ), display_app ) ) return data.as_display_type( display_app, **kwd ) - elif authz_method == 'display_at' and trans.app.host_security_agent.allow_action( trans.request.remote_addr, data.permitted_actions.DATASET_ACCESS, dataset = data ): + elif authz_method == 'display_at' and trans.app.host_security_agent.allow_action( trans.request.remote_addr, + data.permitted_actions.DATASET_ACCESS, + dataset = data ): trans.response.set_content_type( data.get_mime() ) return data.as_display_type( display_app, **kwd ) else: @@ -247,7 +273,15 @@ return trans.show_error_message( "Problem retrieving dataset." ) if id is not None and data.history.user is not None and data.history.user != trans.user: return trans.show_error_message( "This instance of a dataset (%s) in a history does not belong to you." % ( data.id ) ) - if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset=data ): + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + if trans.app.security_agent.allow_action( user, + roles, + data.permitted_actions.DATASET_ACCESS, + dataset=data.dataset ): if data.state == trans.model.Dataset.states.UPLOAD: return trans.show_error_message( "Please wait until this dataset finishes uploading before attempting to edit its metadata." ) params = util.Params( kwd, safe=False ) @@ -313,7 +347,10 @@ elif params.update_roles_button: if not trans.user: return trans.show_error_message( "You must be logged in if you want to change permissions." ) - if trans.app.security_agent.allow_action( trans.user, data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data.dataset ): + if trans.app.security_agent.allow_action( user, + roles, + data.dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS, + dataset = data.dataset ): permissions = {} for k, v in trans.app.model.Dataset.permitted_actions.items(): in_roles = params.get( k + '_in', [] ) diff -r 36f438ce1f82 -r cc4944a62b66 templates/admin/library/browse_library.mako --- a/templates/admin/library/browse_library.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/admin/library/browse_library.mako Fri Aug 28 16:52:58 2009 -0400 @@ -138,12 +138,12 @@ %if show_deleted: <% parent_folders = folder.activatable_folders - parent_datasets = folder.activatable_datasets + parent_datasets = folder.activatable_library_datasets %> %else: <% parent_folders = folder.active_folders - parent_datasets = folder.active_datasets + parent_datasets = folder.active_library_datasets %> %endif %for folder in name_sorted( parent_folders ): diff -r 36f438ce1f82 -r cc4944a62b66 templates/dataset/edit_attributes.mako --- a/templates/dataset/edit_attributes.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/dataset/edit_attributes.mako Fri Aug 28 16:52:58 2009 -0400 @@ -3,6 +3,13 @@ <%def name="title()">${_('Edit Dataset Attributes')}</%def> +<% + user = trans.user + if user: + user_roles = user.all_roles() + else: + user_roles = None +%> <%def name="datatype( dataset, datatypes )"> <select name="datatype"> @@ -134,9 +141,9 @@ </div> <p /> -%if trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset = data ): +%if trans.app.security_agent.allow_action( user, user_roles, data.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=data.dataset ): <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> - ${render_permission_form( data.dataset, data.name, h.url_for( controller='root', action='edit', id=data.id ), trans.user.all_roles() )} + ${render_permission_form( data.dataset, data.name, h.url_for( controller='root', action='edit', id=data.id ), user_roles )} %elif trans.user: <div class="toolForm"> <div class="toolFormTitle">View Permissions</div> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/browse_library.mako --- a/templates/library/browse_library.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/browse_library.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,15 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> -<% from galaxy import util %> +<% + from galaxy import util + from time import strftime + + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> <%def name="title()">Browse data library</%def> <%def name="stylesheets()"> @@ -110,14 +119,14 @@ <a href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, info=True )}"><b>${ldda.name[:60]}</b></a> <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a> <div popupmenu="dataset-${ldda.id}-popup"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a> %else: <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, information=True )}">View this dataset's information</a> %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a> - %if current_version and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + %if current_version and trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, replace_id=library_dataset.id )}">Upload a new version of this dataset</a> %endif %endif @@ -126,24 +135,26 @@ <a class="action-button" href="${h.url_for( controller='library', action='download_dataset_from_folder', id=ldda.id, library_id=library.id )}">Download this dataset</a> %endif </div> - </td> <td>${ldda.message}</td> <td>${uploaded_by}</td> <td>${ldda.create_time.strftime( "%Y-%m-%d" )}</td> - </tr> - + </tr> <% my_row = row_counter.count row_counter.increment() %> </%def> - <%def name="render_folder( folder, folder_pad, created_ldda_ids, library_id, parent=None, row_counter=None )"> <% def show_folder(): - if trans.app.security_agent.check_folder_contents( trans.user, folder ) or trans.app.security_agent.show_library_item( trans.user, folder ): + ## TODO: instead of calling check_folder_contents(), which we've already done prior to getting here, + ## add a new method that will itself call check_folder_contents() and build a list of accessible folders + ## for each library - this should improve performance dor large libraries where the current user can only + ## access a small number of folders. + if trans.app.security_agent.check_folder_contents( user, roles, folder ) or \ + trans.app.security_agent.show_library_item( user, roles, folder ): return True return False if not show_folder: @@ -179,21 +190,21 @@ %endif <a id="folder_img-${folder.id}-popup" class="popup-arrow" style="display: none;">▼</a> <div popupmenu="folder_img-${folder.id}-popup"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=folder ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=folder ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=folder.id )}">Add datasets to this folder</a> <a class="action-button" href="${h.url_for( controller='library', action='folder', new=True, id=folder.id, library_id=library_id )}">Create a new sub-folder in this folder</a> %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): <a class="action-button" href="${h.url_for( controller='library', action='folder', information=True, id=folder.id, library_id=library_id )}">Edit this folder's information</a> %else: <a class="action-button" href="${h.url_for( controller='library', action='folder', information=True, id=folder.id, library_id=library_id )}">View this folder's information</a> %endif %if forms and not folder.info_association: - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): <a class="action-button" href="${h.url_for( controller='library', action='info_template', library_id=library.id, add=True )}">Add an information template to this folder</a> %endif %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=folder ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=folder ): <a class="action-button" href="${h.url_for( controller='library', action='folder', permissions=True, id=folder.id, library_id=library_id )}">Edit this folder's permissions</a> %endif </div> @@ -208,11 +219,11 @@ %for child_folder in name_sorted( folder.active_folders ): ${render_folder( child_folder, pad, created_ldda_ids, library_id, my_row, row_counter )} %endfor - %for library_dataset in name_sorted( folder.active_datasets ): + %for library_dataset in name_sorted( folder.active_library_datasets ): <% selected = created_ldda_ids and library_dataset.library_dataset_dataset_association.id in created_ldda_ids %> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=library_dataset.library_dataset_dataset_association.dataset ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.DATASET_ACCESS, dataset=library_dataset.library_dataset_dataset_association.dataset ): ${render_dataset( library_dataset, selected, library, pad, my_row, row_counter )} %endif %endfor @@ -221,7 +232,7 @@ <h2>Data Library “${library.name}”</h2> <ul class="manage-table-actions"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): %if not deleted: <li> <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library.root_folder.id )}"><span>Add datasets to this library</span></a> @@ -231,17 +242,17 @@ </li> %endif %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): <li><a class="action-button" href="${h.url_for( controller='library', action='library', information=True, id=library.id )}">Edit this library's information</a></li> %else: <li><a class="action-button" href="${h.url_for( controller='library', action='library', information=True, id=library.id )}">View this library's information</a></li> %endif %if forms and not library.info_association: - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=library ): <a class="action-button" href="${h.url_for( controller='library', action='info_template', library_id=library.id, add=True )}">Add an information template to this library</a> %endif %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): <li><a class="action-button" href="${h.url_for( controller='library', action='library', permissions=True, id=library.id )}">Edit this library's permissions</a></li> %endif </ul> @@ -265,7 +276,7 @@ </thead> </tr> <% row_counter = RowCounter() %> - ${render_folder( library.root_folder, 0, created_ldda_ids, library.id, Nonw, row_counter )} + ${render_folder( library.root_folder, 0, created_ldda_ids, library.id, None, row_counter )} <tfoot> <tr> <td colspan="4" style="padding-left: 42px;"> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/common.mako --- a/templates/library/common.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/common.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,65 +1,3 @@ -<% from time import strftime %> - -<%def name="render_dataset( library_dataset, selected, library )"> - <% - ## The received data must always be a LibraryDataset object, but the object id passed to methods from the drop down menu - ## should be the underlying ldda id to prevent id collision ( which could happen when displaying children, which are always - ## lddas ). We also need to make sure we're displaying the latest version of this library_dataset, so we display the attributes - ## from the ldda. - ldda = library_dataset.library_dataset_dataset_association - if ldda.user: - uploaded_by = ldda.user.email - else: - uploaded_by = 'anonymous' - if ldda == ldda.library_dataset.library_dataset_dataset_association: - current_version = True - else: - current_version = False - %> - <div class="historyItemWrapper historyItem historyItem-${ldda.state}" id="libraryItem-${ldda.id}"> - ## Header row for library items (name, state, action buttons) - <div class="historyItemTitleBar"> - <table cellspacing="0" cellpadding="0" border="0" width="100%"> - <tr> - <td width="*"> - %if selected: - <input type="checkbox" name="ldda_ids" value="${ldda.id}" checked/> - %else: - <input type="checkbox" name="ldda_ids" value="${ldda.id}"/> - %endif - <a href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, info=True )}"><b>${ldda.name[:60]}</b></a> - <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a> - <div popupmenu="dataset-${ldda.id}-popup"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): - <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a> - %else: - <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, information=True )}">View this dataset's information</a> - %endif - ## We're disabling the ability to add templates at the LDDA and LibraryDataset level, but will leave this here for possible future use - ##%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_ADD, library_item=ldda.library_dataset ): - ## <a class="action-button" href="${h.url_for( controller='library', action='info_template', library_id=library.id, library_dataset_id=library_dataset.id, new_template=True )}">Add an information template to this dataset</a> - ##%endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): - <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a> - %if current_version and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): - <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library.id, folder_id=library_dataset.folder.id, replace_id=library_dataset.id )}">Upload a new version of this dataset</a> - %endif - %endif - %if ldda.has_data: - <a class="action-button" href="${h.url_for( controller='library', action='datasets', library_id=library.id, ldda_ids=str( ldda.id ), do_action='add' )}">Import this dataset into your current history</a> - <a class="action-button" href="${h.url_for( controller='library', action='download_dataset_from_folder', id=ldda.id, library_id=library.id )}">Download this dataset</a> - %endif - </div> - </td> - <td width="500">${ldda.message}</td> - <td width="150">${uploaded_by}</td> - <td width="60">${ldda.create_time.strftime( "%Y-%m-%d" )}</td> - </tr> - </table> - </div> - </div> -</%def> - <%def name="render_template_info( library_item, library_id, widgets, editable=True )"> <% library_item_type = 'unknown type' @@ -76,13 +14,18 @@ elif isinstance( library_item, trans.app.model.LibraryDatasetDatasetAssociation ): library_item_type = 'library_dataset_dataset_association' library_item_desc = 'library dataset' + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None %> %if widgets: <p/> <div class="toolForm"> <div class="toolFormTitle">Other information about ${library_item_desc} ${library_item.name}</div> <div class="toolFormBody"> - %if editable and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library_item ): + %if editable and trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library_item ): <form name="edit_info" action="${h.url_for( controller='library', action='edit_template_info', library_id=library_id, num_widgets=len( widgets ) )}" method="post"> <input type="hidden" name="library_item_id" value="${library_item.id}"/> <input type="hidden" name="library_item_type" value="${library_item_type}"/> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/folder_info.mako --- a/templates/library/folder_info.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/folder_info.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/library/common.mako" import="render_template_info" /> + +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> <br/><br/> <ul class="manage-table-actions"> @@ -16,7 +24,7 @@ <div class="toolForm"> <div class="toolFormTitle">Edit folder name and description</div> <div class="toolFormBody"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=folder ): <form name="folder" action="${h.url_for( controller='library', action='folder', rename=True, id=folder.id, library_id=library_id )}" method="post" > <div class="form-row"> <label>Name:</label> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/folder_permissions.mako --- a/templates/library/folder_permissions.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/folder_permissions.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> + +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> <br/><br/> <ul class="manage-table-actions"> @@ -13,6 +21,6 @@ ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=folder ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=folder ): ${render_permission_form( folder, folder.name, h.url_for( controller='library', action='folder', id=folder.id, library_id=library_id, permissions=True ), trans.user.all_roles() )} %endif diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/ldda_edit_info.mako --- a/templates/library/ldda_edit_info.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/ldda_edit_info.mako Fri Aug 28 16:52:58 2009 -0400 @@ -2,6 +2,14 @@ <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/library/common.mako" import="render_template_info" /> <% from galaxy import util %> + +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> %if ldda == ldda.library_dataset.library_dataset_dataset_association: <b><i>This is the latest version of this library dataset</i></b> @@ -32,7 +40,7 @@ </select> </%def> -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): <div class="toolForm"> <div class="toolFormTitle">Edit attributes of ${ldda.name}</div> <div class="toolFormBody"> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/ldda_info.mako --- a/templates/library/ldda_info.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/ldda_info.mako Fri Aug 28 16:52:58 2009 -0400 @@ -8,6 +8,11 @@ current_version = True else: current_version = False + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None %> %if current_version: @@ -39,15 +44,15 @@ Information about ${ldda.name} <a id="dataset-${ldda.id}-popup" class="popup-arrow" style="display: none;">▼</a> <div popupmenu="dataset-${ldda.id}-popup"> - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, edit_info=True )}">Edit this dataset's information</a> %else: <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, information=True )}">View this dataset's information</a> %endif - %if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): + %if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS, dataset=ldda.dataset ) and trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, id=ldda.id, permissions=True )}">Edit this dataset's permissions</a> %endif - %if current_version and trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): + %if current_version and trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=ldda.library_dataset ): <a class="action-button" href="${h.url_for( controller='library', action='library_dataset_dataset_association', library_id=library_id, folder_id=ldda.library_dataset.folder.id, replace_id=ldda.library_dataset.id )}">Upload a new version of this dataset</a> %endif %if ldda.has_data: @@ -92,6 +97,8 @@ <div><pre id="peek${ldda.id}" class="peek">${ldda.display_peek()}</pre></div> %endif ## Recurse for child datasets + ## TODO: eliminate this - child datasets are deprecated, and where does + ## render_dataset() come from anyway - it's not imported! %if len( ldda.visible_children ) > 0: <div> There are ${len( ldda.visible_children )} secondary datasets. diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/library_dataset_info.mako --- a/templates/library/library_dataset_info.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/library_dataset_info.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/library/common.mako" import="render_template_info" /> + +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> %if library_dataset == library_dataset.library_dataset_dataset_association.library_dataset: <b><i>This is the latest version of this library dataset</i></b> @@ -19,7 +27,7 @@ ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library_dataset ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library_dataset ): <div class="toolForm"> <div class="toolFormTitle">Edit attributes of ${library_dataset.name}</div> <div class="toolFormBody"> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/library_dataset_permissions.mako --- a/templates/library/library_dataset_permissions.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/library_dataset_permissions.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/dataset/security_common.mako" import="render_permission_form" />> + +<% + user = trans.user + if user: + user_roles = user.all_roles() + else: + user_roles = None +%> %if library_dataset == library_dataset.library_dataset_dataset_association.library_dataset: <b><i>This is the latest version of this library dataset</i></b> @@ -19,7 +27,7 @@ ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_manage, library_item=library_dataset ): +%if trans.app.security_agent.allow_action( user, user_roles, trans.app.security_agent.permitted_actions.LIBRARY_manage, library_item=library_dataset ): <% roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.table.c.name ).all() %> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/library_info.mako --- a/templates/library/library_info.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/library_info.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/library/common.mako" import="render_template_info" /> + +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> <br/><br/> <ul class="manage-table-actions"> @@ -13,7 +21,7 @@ ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): <div class="toolForm"> <div class="toolFormTitle">Change library name and description</div> <div class="toolFormBody"> diff -r 36f438ce1f82 -r cc4944a62b66 templates/library/library_permissions.mako --- a/templates/library/library_permissions.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/library/library_permissions.mako Fri Aug 28 16:52:58 2009 -0400 @@ -1,6 +1,14 @@ <%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> + +<% + user = trans.user + if user: + user_roles = user.all_roles() + else: + user_roles = None +%> <br/><br/> <ul class="manage-table-actions"> @@ -13,7 +21,7 @@ ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): +%if trans.app.security_agent.allow_action( user, user_roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): <% roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.table.c.name ).all() %> diff -r 36f438ce1f82 -r cc4944a62b66 templates/mobile/history/detail.mako --- a/templates/mobile/history/detail.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/mobile/history/detail.mako Fri Aug 28 16:52:58 2009 -0400 @@ -36,8 +36,14 @@ <div class="secondary"> ## Body for history items, extra info and actions, data "peek" - - %if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): + <% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None + %> + %if not trans.app.security_agent.allow_action( user, roles, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): <div>You do not have permission to view this dataset.</div> %elif data_state == "queued": <div>Job is waiting to run</div> diff -r 36f438ce1f82 -r cc4944a62b66 templates/mobile/manage_library.mako --- a/templates/mobile/manage_library.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/mobile/manage_library.mako Fri Aug 28 16:52:58 2009 -0400 @@ -3,11 +3,19 @@ <%namespace file="/dataset/security_common.mako" import="render_permission_form" /> <%namespace file="/library/common.mako" import="render_template_info" /> +<% + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None +%> + %if msg: ${render_msg( msg, messagetype )} %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY, library_item=library ): <div class="toolForm"> <div class="toolFormTitle">Change library name and description</div> <div class="toolFormBody"> @@ -53,7 +61,7 @@ </div> </div> %endif -%if trans.app.security_agent.allow_action( trans.user, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): +%if trans.app.security_agent.allow_action( user, roles, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE, library_item=library ): <% roles = trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.table.c.name ).all() %> diff -r 36f438ce1f82 -r cc4944a62b66 templates/root/history_common.mako --- a/templates/root/history_common.mako Fri Aug 28 15:59:16 2009 -0400 +++ b/templates/root/history_common.mako Fri Aug 28 16:52:58 2009 -0400 @@ -2,12 +2,17 @@ ## Render the dataset `data` as history item, using `hid` as the displayed id <%def name="render_dataset( data, hid, show_deleted_on_refresh = False )"> <% - if data.state in ['no state','',None]: - data_state = "queued" - else: - data_state = data.state + if data.state in ['no state','',None]: + data_state = "queued" + else: + data_state = data.state + user = trans.user + if user: + roles = user.all_roles() + else: + roles = None %> - %if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): + %if not trans.app.security_agent.allow_action( user, roles, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): <div class="historyItemWrapper historyItem historyItem-${data_state} historyItem-noPermission" id="historyItem-${data.id}"> %else: <div class="historyItemWrapper historyItem historyItem-${data_state}" id="historyItem-${data.id}"> @@ -41,7 +46,7 @@ ## Body for history items, extra info and actions, data "peek" <div id="info${data.id}" class="historyItemBody"> - %if not trans.app.security_agent.allow_action( trans.user, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): + %if not trans.app.security_agent.allow_action( user, roles, data.permitted_actions.DATASET_ACCESS, dataset = data.dataset ): <div>You do not have permission to view this dataset.</div> %elif data_state == "upload": <div>Dataset is uploading</div> diff -r 36f438ce1f82 -r cc4944a62b66 test/base/twilltestcase.py --- a/test/base/twilltestcase.py Fri Aug 28 15:59:16 2009 -0400 +++ b/test/base/twilltestcase.py Fri Aug 28 16:52:58 2009 -0400 @@ -1229,7 +1229,7 @@ tc.fv( '1', 'new_element_description_1', ele_help_1.replace( '+', ' ' ) ) tc.submit( 'new_info_template_button' ) self.home() - def add_folder( self, library_id, folder_id, name='Folder One', description='NThis is Folder One' ): + def add_folder( self, library_id, folder_id, name='Folder One', description='This is Folder One' ): """Create a new folder""" self.home() self.visit_url( "%s/admin/folder?library_id=%s&id=%s&new=True" % ( self.url, library_id, folder_id ) ) diff -r 36f438ce1f82 -r cc4944a62b66 universe_wsgi.ini.sample --- a/universe_wsgi.ini.sample Fri Aug 28 15:59:16 2009 -0400 +++ b/universe_wsgi.ini.sample Fri Aug 28 16:52:58 2009 -0400 @@ -25,6 +25,11 @@ #database_engine_option_echo_pool = true #database_engine_option_pool_size = 10 #database_engine_option_max_overflow = 20 + +# If using MySQL, see: +#
http://rapd.wordpress.com/2008/03/02/sqlalchemy-sqlerror-operationalerror-2…
+# To handle this issue, try the following setting: +#database_engine_option_pool_recycle = 7200 # Where dataset files are saved file_path = database/files
1
0
0
0
[hg] galaxy 2642: CSS code for tagging
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/116e79410240
changeset: 2642:116e79410240 user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:29:47 2009 -0400 description: CSS code for tagging 2 file(s) affected in this change: static/june_2007_style/autocomplete_tagging.css.tmpl static/june_2007_style/blue/autocomplete_tagging.css diffs (276 lines): diff -r 6b66a5e142ab -r 116e79410240 static/june_2007_style/autocomplete_tagging.css.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/june_2007_style/autocomplete_tagging.css.tmpl Fri Aug 28 15:29:47 2009 -0400 @@ -0,0 +1,133 @@ +/****************************************************************************/ +/* JQuery autocomplete code */ +/****************************************************************************/ + +.ac_results { + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; +} + +.ac_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.ac_results li { + padding: 2px 5px; + cursor: default; + display: block; + /* + if width will be 100% horizontal scrollbar will apear + when scroll mode will be used + */ + /*width: 100%;*/ + /* font: menu; */ + font-size: 12px; + /* + it is very important, if line-height not setted or setted + in relative units scroll will be broken in firefox + */ + line-height: 16px; + overflow: hidden; +} + +.ac_loading { + background: white url('indicator.gif') right center no-repeat; +} + +.ac_odd { + background-color: #fff; /* #eee */ + margin-left: 0.3em; +} + +.ac_even { + margin-left: 0.3em; +} + +.ac_over { + background-color: #0A246A; + color: white; +} + +.ac_header { + font-style: normal; + color: gray; + border-bottom: 0.1em solid gray; +} + +/****************************************************************************/ +/* Custom code for supporting tags */ +/****************************************************************************/ +.tag-area { + width: 100%; + cursor: pointer; + border: solid 1px #eee; +} + +.active-tag-area { + background-color: white; +} + +.toggle-link +{ + font-weight: bold; + padding: 0.3em; + margin-bottom: 1em; + width: 100%; + padding: 0.2em 0em 0.2em 0em; +} + +.tag-button { + width: auto; + color: #444; + text-decoration: none; + display: inline-block; + cursor: pointer; + margin: 0.2em; + border: 0; + padding: 0.1em 0.5em 0.1em 0.5em; + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + border-radius: .5em; + background:#bbb; +} + +.tag-button img +{ + padding-left: 0.4em; +} + +.tag-button .tag-name:hover +{ + color: white; +} + +.add-tag-button +{ + margin-bottom: 0.3em; + vertical-align: middle; + padding: 0.3em; +} + +.add-tag-button:hover +{ + cursor: pointer; +} + +.tag-input { + vertical-align: bottom; + border: none; + outline: none; +} + +.delete-tag-img +{ + + margin-left: 0.3em +} \ No newline at end of file diff -r 6b66a5e142ab -r 116e79410240 static/june_2007_style/blue/autocomplete_tagging.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/june_2007_style/blue/autocomplete_tagging.css Fri Aug 28 15:29:47 2009 -0400 @@ -0,0 +1,133 @@ +/****************************************************************************/ +/* JQuery autocomplete code */ +/****************************************************************************/ + +.ac_results { + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; +} + +.ac_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.ac_results li { + padding: 2px 5px; + cursor: default; + display: block; + /* + if width will be 100% horizontal scrollbar will apear + when scroll mode will be used + */ + /*width: 100%;*/ + /* font: menu; */ + font-size: 12px; + /* + it is very important, if line-height not setted or setted + in relative units scroll will be broken in firefox + */ + line-height: 16px; + overflow: hidden; +} + +.ac_loading { + background: white url('indicator.gif') right center no-repeat; +} + +.ac_odd { + background-color: #fff; /* #eee */ + margin-left: 0.3em; +} + +.ac_even { + margin-left: 0.3em; +} + +.ac_over { + background-color: #0A246A; + color: white; +} + +.ac_header { + font-style: normal; + color: gray; + border-bottom: 0.1em solid gray; +} + +/****************************************************************************/ +/* Custom code for supporting tags */ +/****************************************************************************/ +.tag-area { + width: 100%; + cursor: pointer; + border: solid 1px #eee; +} + +.active-tag-area { + background-color: white; +} + +.toggle-link +{ + font-weight: bold; + padding: 0.3em; + margin-bottom: 1em; + width: 100%; + padding: 0.2em 0em 0.2em 0em; +} + +.tag-button { + width: auto; + color: #444; + text-decoration: none; + display: inline-block; + cursor: pointer; + margin: 0.2em; + border: 0; + padding: 0.1em 0.5em 0.1em 0.5em; + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + border-radius: .5em; + background:#bbb; +} + +.tag-button img +{ + padding-left: 0.4em; +} + +.tag-button .tag-name:hover +{ + color: white; +} + +.add-tag-button +{ + margin-bottom: 0.3em; + vertical-align: middle; + padding: 0.3em; +} + +.add-tag-button:hover +{ + cursor: pointer; +} + +.tag-input { + vertical-align: bottom; + border: none; + outline: none; +} + +.delete-tag-img +{ + + margin-left: 0.3em +} \ No newline at end of file
1
0
0
0
[hg] galaxy 2643: JS files for tagging
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/1835c027763a
changeset: 2643:1835c027763a user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:31:06 2009 -0400 description: JS files for tagging 2 file(s) affected in this change: static/scripts/autocomplete_tagging.js static/scripts/jquery.autocomplete.js diffs (1285 lines): diff -r 116e79410240 -r 1835c027763a static/scripts/autocomplete_tagging.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/autocomplete_tagging.js Fri Aug 28 15:31:06 2009 -0400 @@ -0,0 +1,453 @@ +/** + * JQuery extension for tagging with autocomplete. + * @author: Jeremy Goecks + * @require: jquery.autocomplete plugin + */ +var ac_tag_area_id_gen = 1; + +jQuery.fn.autocomplete_tagging = function(options) { + + // + // Set up function defaults. + // + var defaults = + { + get_toggle_link_text_fn: function(tags) + { + var text = ""; + var num_tags = array_length(tags); + if (num_tags != 0) + text = num_tags + (num_tags != 0 ? " Tags" : " Tag"); + else + // No tags. + text = "Add tags"; + return text; + }, + tag_click_fn : function (tag) { }, + input_size: 20, + in_form: false, + tags : {}, + use_toggle_link: true, + item_id: "", + add_tag_img: "", + add_tag_img_rollover: "", + delete_tag_img: "", + ajax_autocomplete_tag_url: "", + ajax_retag_url: "", + ajax_delete_tag_url: "", + ajax_add_tag_url: "" + }; + + // + // Extend object. + // + var settings = jQuery.extend(defaults, options); + + // + // Create core elements: tag area and TODO. + // + + // Tag area. + var area_id = "tag-area-" + (ac_tag_area_id_gen)++; + var tag_area = $("<div></div>").attr("id", area_id).addClass("tag-area"); + this.append(tag_area); + + // + // Returns the number of keys (elements) in an array/dictionary. + // + var array_length = function(an_array) + { + if (an_array.length) + return an_array.length; + + var count = 0; + for (element in an_array) + count++; + return count; + }; + + // + // Function to build toggle link. + // + var build_toggle_link = function() + { + var link_text = settings.get_toggle_link_text_fn(settings.tags); + var toggle_link = $("<a href='/history/tags'>" + link_text + "</a>").addClass("toggle-link"); + // Link toggles the display state of the tag area. + toggle_link.click( function() + { + // Take special actions depending on whether toggle is showing or hiding link. + var showing_tag_area = (tag_area.css("display") == "none"); + var after_toggle_fn; + if (showing_tag_area) + { + after_toggle_fn = function() + { + // If there are no tags, go right to editing mode by generating a + // click on the area. + var num_tags = array_length(settings.tags); + if (num_tags == 0) + tag_area.click(); + }; + } + else // Hiding area. + { + after_toggle_fn = function() + { + tag_area.blur(); + }; + } + tag_area.slideToggle("fast", after_toggle_fn); + + return false; + }); + + return toggle_link; + }; + + // Add toggle link. + var toggle_link = build_toggle_link(); + if (settings.use_toggle_link) + { + this.prepend(toggle_link); + } + + // + // Function to build other elements. + // + + // + // Return a string that contains the contents of an associative array. This is + // a debugging method. + // + var assoc_array_to_str = function(an_array) + { + // Convert associative array to simple array and then join array elements. + var array_str_list = new Array(); + for (key in an_array) + array_str_list[array_str_list.length] = key + "-->" + an_array[key]; + + return "{" + array_str_list.join(",") + "}" + }; + + // + // Collapse tag name + value into a single string. + // + var build_tag_str = function(tag_name, tag_value) + { + return tag_name + ( (tag_value != "" && tag_value) ? ":" + tag_value : ""); + }; + + // + // Get tag name and value from a string. + // + var get_tag_name_and_value = function(tag_str) + { + return tag_str.split(":"); + }; + + // + // Add "add tag" button. + // + var build_add_tag_button = function(tag_input_field) + { + var add_tag_button = $("<img src='" + settings.add_tag_img + "' rollover='" + settings.add_tag_img_rollover + "'/>").addClass("add-tag-button"); + + add_tag_button.click( function() + { + // Hide button. + $(this).hide(); + + // Clicking on button is the same as clicking on the tag area. + tag_area.click(); + + return false; + }); + + return add_tag_button; + }; + + // + // Function that builds a tag button. + // + var build_tag_button = function(tag_str) + { + // Build "delete tag" image and handler. + var delete_img = $("<img src='" + settings.delete_tag_img + "'/>").addClass("delete-tag-img"); + delete_img.mouseenter( function () + { + $(this).attr("src", settings.delete_tag_img_rollover); + }); + delete_img.mouseleave( function () + { + $(this).attr("src", settings.delete_tag_img); + }); + delete_img.click( function () + { + // Tag button is image's parent. + var tag_button = $(this).parent(); + + // Get tag name. + var tag_name_elt = tag_button.find(".tag-name").eq(0); + var tag_str = tag_name_elt.text(); + var tag_name = get_tag_name_and_value(tag_str)[0]; + + // TODO: should remove succeed if tag is not already applied to + // history? + tag_button.remove(); + + // Remove tag from local list for consistency. + delete settings.tags[tag_name]; + + // Update toggle link text. + var new_text = settings.get_toggle_link_text_fn(settings.tags); + toggle_link.text(new_text); + + // Delete tag. + $.ajax({ + url: settings.ajax_delete_tag_url, + data: { tag_name: tag_name }, + error: function() + { + // Failed. + alert( "Remove tag failed" ); + }, + success: function() + { + } + }); + + return true; + }); + + // Build tag button. + var tag_name_elt = $("<span>" + tag_str + "</span>").addClass("tag-name"); + tag_name_elt.click( function() + { + settings.tag_click_fn(tag_str); + return true; + }); + + var tag_button = $("<span></span>").addClass("tag-button"); + tag_button.append(tag_name_elt); + tag_button.append(delete_img); + + return tag_button; + }; + + // + // Build input + autocompete for tag. + // + var build_tag_input = function(tag_text) + { + // If element is in form, tag input is a textarea; otherwise element is a input type=text. + var t; + if (settings.in_form) + t = $( "<textarea id='history-tag-input' rows='1' cols='" + + settings.input_size + "' value='" + tag_text + "'></textarea>" ); + else // element not in form. + t = $( "<input id='history-tag-input' type='text' size='" + + settings.input_size + "' value='" + tag_text + "'></input>" ); + t.keyup( function( e ) + { + if ( e.keyCode == 27 ) + { + // Escape key + $(this).trigger( "blur" ); + } else if ( + ( e.keyCode == 13 ) || // Return Key + ( e.keyCode == 188 ) || // Comma + ( e.keyCode == 32 ) // Space + ) + { + // + // Check input. + // + + new_value = this.value; + + // Do nothing if return key was used to autocomplete. + if (return_key_pressed_for_autocomplete == true) + { + return_key_pressed_for_autocomplete = false; + return false; + } + + // Suppress space after a ":" + if ( new_value.indexOf(": ", new_value.length - 2) != -1) + { + this.value = new_value.substring(0, new_value.length-1); + return false; + } + + // Remove trigger keys from input. + if ( (e.keyCode == 188) || (e.keyCode == 32) ) + new_value = new_value.substring( 0 , new_value.length - 1 ); + + // Trim whitespace. + new_value = new_value.replace(/^\s+|\s+$/g,""); + + // Too short? + if (new_value.length < 3) + return false; + + // + // New tag OK - apply it. + // + + this.value = ""; + + // Add button for tag after all other tag buttons. + var new_tag_button = build_tag_button(new_value); + var tag_buttons = tag_area.children(".tag-button"); + if (tag_buttons.length != 0) + { + var last_tag_button = tag_buttons.slice(tag_buttons.length-1); + last_tag_button.after(new_tag_button); + } + else + tag_area.prepend(new_tag_button); + + // Add tag to internal list. + var tag_name_and_value = new_value.split(":"); + settings.tags[tag_name_and_value[0]] = tag_name_and_value[1]; + + // Update toggle link text. + var new_text = settings.get_toggle_link_text_fn(settings.tags); + toggle_link.text(new_text); + + // Commit tag to server. + var $this = $(this); + $.ajax({ + url: settings.ajax_add_tag_url, + data: { new_tag: new_value }, + error: function() + { + // Remove tag and show alert. + new_tag_button.remove(); + var new_text = settings.get_toggle_link_text_fn(settings.tags); + toggle_link.text(new_text); + alert( "Add tag failed" ); + }, + success: function() + { + // Flush autocomplete cache because it's not out of date. + // TODO: in the future, we could remove the particular item + // that was chosen from the cache rather than flush it. + $this.flushCache(); + } + }); + + return false; + } + }); + + // Add autocomplete to input. + var format_item_func = function(key, row_position, num_rows, value, search_term) { + tag_name_and_value = value.split(":"); + return (tag_name_and_value.length == 1 ? tag_name_and_value[0] :tag_name_and_value[1]); + //var array = new Array(key, value, row_position, num_rows, + //search_term ); return "\"" + array.join("*") + "\""; + } + var autocomplete_options = + { selectFirst: false, formatItem : format_item_func, autoFill: false, highlight: false }; + + t.autocomplete(settings.ajax_autocomplete_tag_url, autocomplete_options); + + t.addClass("tag-input"); + + return t; + }; + + // + // Build tag area. + // + + // Add tag buttons for each current tag to the tag area. + for (tag_name in settings.tags) + { + var tag_value = settings.tags[tag_name]; + var tag_str = build_tag_str(tag_name, tag_value); + var tag_button = build_tag_button(tag_str, toggle_link, settings.tags); + tag_area.append(tag_button); + } + + // Add tag input field and "add tag" button. + var tag_input_field = build_tag_input(""); + var add_tag_button = build_add_tag_button(tag_input_field); + + // When the tag area blurs, go to "view tag" mode. + tag_area.blur( function(e) + { + add_tag_button.show(); + tag_input_field.hide(); + tag_area.removeClass("active-tag-area"); + }); + + tag_area.append(add_tag_button); + tag_area.append(tag_input_field); + tag_input_field.hide(); + + // On click, enable user to add tags. + tag_area.click( function(e) + { + var is_active = $(this).hasClass("active-tag-area"); + + // If a "delete image" object was pressed and area is inactive, do nothing. + if ($(e.target).hasClass("delete-tag-img") && !is_active) + return false; + + // If a "tag name" object was pressed and area is inactive, do nothing. + if ($(e.target).hasClass("tag-name") && !is_active) + return false; + + // Hide add tag button, show tag_input field. Change background to show + // area is active. + $(this).addClass("active-tag-area"); + add_tag_button.hide(); + tag_input_field.show(); + tag_input_field.focus(); + + // Add handler to document that will call blur when the tag area is blurred; + // a tag area is blurred when a user clicks on an element outside the area. + var handle_document_click = function(e) + { + var tag_area_id = tag_area.attr("id"); + // Blur the tag area if the element clicked on is not in the tag area. + if ( + ($(e.target).attr("id") != tag_area_id) && + ($(e.target).parents().filter(tag_area_id).length == 0) + ) + { + tag_area.blur(); + $(document).unbind("click", handle_document_click); + } + }; + // TODO: we should attach the click handler to all frames in order to capture + // clicks outside the frame that this element is in. + //window.parent.document.onclick = handle_document_click; + //var temp = $(window.parent.document.body).contents().find("iframe").html(); + //alert(temp); + //$(document).parent().click(handle_document_click); + $(window).click(handle_document_click); + + return false; + }); + + // If using toggle link, hide the tag area. Otherwise, if there are no tags, + // hide the "add tags" button and show the input field. + if (settings.use_toggle_link) + tag_area.hide(); + else + { + var num_tags = array_length(settings.tags); + if (num_tags == 0) + { + add_tag_button.hide(); + tag_input_field.show(); + } + } + + + return this.addClass("tag-element"); +} diff -r 116e79410240 -r 1835c027763a static/scripts/jquery.autocomplete.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/jquery.autocomplete.js Fri Aug 28 15:31:06 2009 -0400 @@ -0,0 +1,824 @@ +/* + * Autocomplete - jQuery plugin 1.0.2 + * + * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + *
http://www.opensource.org/licenses/mit-license.php
+ *
http://www.gnu.org/licenses/gpl.html
+ * + * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $ + * + */ + +String.prototype.endsWith = function(str) {return (this.match(str+"$")==str)} + + +var return_key_pressed_for_autocomplete = false; + +;(function($) { + +$.fn.extend({ + autocomplete: function(urlOrData, options) { + var isUrl = typeof urlOrData == "string"; + options = $.extend({}, $.Autocompleter.defaults, { + url: isUrl ? urlOrData : null, + data: isUrl ? null : urlOrData, + delay: isUrl ? $.Autocompleter.defaults.delay : 10, + max: options && !options.scroll ? 10 : 150 + }, options); + + // if highlight is set to false, replace it with a do-nothing function + options.highlight = options.highlight || function(value) { return value; }; + + // if the formatMatch option is not specified, then use formatItem for backwards compatibility + options.formatMatch = options.formatMatch || options.formatItem; + + return this.each(function() { + new $.Autocompleter(this, options); + }); + }, + result: function(handler) { + return this.bind("result", handler); + }, + search: function(handler) { + return this.trigger("search", [handler]); + }, + flushCache: function() { + return this.trigger("flushCache"); + }, + setOptions: function(options){ + return this.trigger("setOptions", [options]); + }, + unautocomplete: function() { + return this.trigger("unautocomplete"); + } +}); + +$.Autocompleter = function(input, options) { + + var KEY = { + UP: 38, + DOWN: 40, + DEL: 46, + TAB: 9, + RETURN: 13, + ESC: 27, + COMMA: 188, + PAGEUP: 33, + PAGEDOWN: 34, + BACKSPACE: 8, + COLON: 16 + }; + + // Create $ object for input element + var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); + + var timeout; + var previousValue = ""; + var cache = $.Autocompleter.Cache(options); + var hasFocus = 0; + var lastKeyPressCode; + var config = { + mouseDownOnSelect: false + }; + var select = $.Autocompleter.Select(options, input, selectCurrent, config); + + var blockSubmit; + + // prevent form submit in opera when selecting with return key + $.browser.opera && $(input.form).bind("submit.autocomplete", function() { + if (blockSubmit) { + blockSubmit = false; + return false; + } + }); + + // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all + $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { + // track last key pressed + lastKeyPressCode = event.keyCode; + switch(event.keyCode) { + + case KEY.UP: + event.preventDefault(); + if ( select.visible() ) { + select.prev(); + } else { + onChange(0, true); + } + break; + + case KEY.DOWN: + event.preventDefault(); + if ( select.visible() ) { + select.next(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEUP: + event.preventDefault(); + if ( select.visible() ) { + select.pageUp(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEDOWN: + event.preventDefault(); + if ( select.visible() ) { + select.pageDown(); + } else { + onChange(0, true); + } + break; + + // matches also semicolon + case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: + case KEY.TAB: + case KEY.RETURN: + if (event.keyCode == KEY.RETURN) + return_key_pressed_for_autocomplete = false; + if( selectCurrent() ) { + // stop default to prevent a form submit, Opera needs special handling + event.preventDefault(); + blockSubmit = true; + + // JG: set flag to indicate that a selection just occurred using the return key. FYI: + // event.stopPropagation() does not work. + if (event.keyCode == KEY.RETURN) + return_key_pressed_for_autocomplete = true; + + return false; + } + + case KEY.ESC: + select.hide(); + break; + case KEY.COLON: + break; + + default: + clearTimeout(timeout); + timeout = setTimeout(onChange, options.delay); + break; + } + }).focus(function(){ + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).blur(function() { + hasFocus = 0; + if (!config.mouseDownOnSelect) { + // JG: if blur and user is not selecting with mouse, hide + // object. + select.hide(); + } + return this; + }).click(function() { + // show select when clicking in a focused field + if ( hasFocus++ > 1 && !select.visible() ) { + onChange(0, true); + } + return this; + }).bind("search", function() { + // TODO why not just specifying both arguments? + var fn = (arguments.length > 1) ? arguments[1] : null; + function findValueCallback(q, data) { + var result; + if( data && data.length ) { + for (var i=0; i < data.length; i++) { + if( data[i].result.toLowerCase() == q.toLowerCase() ) { + result = data[i]; + break; + } + } + } + if( typeof fn == "function" ) fn(result); + else $input.trigger("result", result && [result.data, result.value]); + } + $.each(trimWords($input.val()), function(i, value) { + request(value, findValueCallback, findValueCallback); + }); + + return this; + }).bind("flushCache", function() { + cache.flush(); + }).bind("setOptions", function() { + $.extend(options, arguments[1]); + // if we've updated the data, repopulate + if ( "data" in arguments[1] ) + cache.populate(); + }).bind("unautocomplete", function() { + select.unbind(); + $input.unbind(); + $(input.form).unbind(".autocomplete"); + }); + + + function selectCurrent() { + var selected = select.selected(); + if( !selected ) + return false; + + var v = selected.result; + previousValue = v; + + if ( options.multiple ) { + var words = trimWords($input.val()); + if ( words.length > 1 ) { + v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v; + } + v += options.multipleSeparator; + } + + $input.val(v); + hideResultsNow(); + $input.trigger("result", [selected.data, selected.value]); + return true; + } + + function onChange(crap, skipPrevCheck) { + if( lastKeyPressCode == KEY.DEL ) { + select.hide(); + return; + } + + var currentValue = $input.val(); + + if ( !skipPrevCheck && currentValue == previousValue ) + return; + + previousValue = currentValue; + + currentValue = lastWord(currentValue); + if ( currentValue.length >= options.minChars) { + $input.addClass(options.loadingClass); + if (!options.matchCase) + currentValue = currentValue.toLowerCase(); + request(currentValue, receiveData, hideResultsNow); + } else { + stopLoading(); + select.hide(); + } + }; + + function trimWords(value) { + if ( !value ) { + return [""]; + } + var words = value.split( options.multipleSeparator ); + var result = []; + $.each(words, function(i, value) { + if ( $.trim(value) ) + result[i] = $.trim(value); + }); + return result; + } + + function lastWord(value) { + if ( !options.multiple ) + return value; + var words = trimWords(value); + return words[words.length - 1]; + } + + // fills in the input box w/the first match (assumed to be the best match) + // q: the term entered + // sValue: the first matching result + function autoFill(q, sValue){ + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + // if the last user key pressed was backspace, don't autofill + if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) { + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); + // select the portion of the value not typed by the user (so the next character will erase) + $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length); + } + }; + + function hideResults() { + clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + var wasVisible = select.visible(); + select.hide(); + clearTimeout(timeout); + stopLoading(); + if (options.mustMatch) { + // call search and run callback + $input.search( + function (result){ + // if no value found, clear the input box + if( !result ) { + if (options.multiple) { + var words = trimWords($input.val()).slice(0, -1); + $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); + } + else + $input.val( "" ); + } + } + ); + } + if (wasVisible) + // position cursor at end of input field + $.Autocompleter.Selection(input, input.value.length, input.value.length); + }; + + function receiveData(q, data) { + if ( data && data.length && hasFocus ) { + stopLoading(); + select.display(data, q); + autoFill(q, data[0].value); + select.show(); + } else { + hideResultsNow(); + } + }; + + function request(term, success, failure) { + if (!options.matchCase) + term = term.toLowerCase(); + var data = cache.load(term); + + // JG: hack: if term ends with ':', kill data to force an ajax request. + if (term.endsWith(":")) + data = null; + + // recieve the cached data + if (data && data.length) { + success(term, data); + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + var extraParams = { + timestamp: +new Date() + }; + $.each(options.extraParams, function(key, param) { + extraParams[key] = typeof param == "function" ? param() : param; + }); + + $.ajax({ + // try to leverage ajaxQueue plugin to abort previous requests + mode: "abort", + // limit abortion to this input + port: "autocomplete" + input.name, + dataType: options.dataType, + url: options.url, + data: $.extend({ + q: lastWord(term), + limit: options.max + }, extraParams), + success: function(data) { + var parsed = options.parse && options.parse(data) || parse(data); + cache.add(term, parsed); + success(term, parsed); + } + }); + } else { + // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match + select.emptyList(); + failure(term); + } + }; + + function parse(data) { + var parsed = []; + var rows = data.split("\n"); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + row = row.split("|"); + parsed[parsed.length] = { + data: row, + value: row[0], + result: options.formatResult && options.formatResult(row, row[0]) || row[0] + }; + } + } + return parsed; + }; + + function stopLoading() { + $input.removeClass(options.loadingClass); + }; + +}; + +$.Autocompleter.defaults = { + inputClass: "ac_input", + resultsClass: "ac_results", + loadingClass: "ac_loading", + minChars: 1, + delay: 400, + matchCase: false, + matchSubset: true, + matchContains: false, + cacheLength: 10, + max: 100, + mustMatch: false, + extraParams: {}, + selectFirst: true, + formatItem: function(row) { return row[0]; }, + formatMatch: null, + autoFill: false, + width: 0, + multiple: false, + multipleSeparator: ", ", + highlight: function(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"); + }, + scroll: true, + scrollHeight: 180 +}; + +$.Autocompleter.Cache = function(options) { + + var data = {}; + var length = 0; + + function matchSubset(s, sub) { + if (!options.matchCase) + s = s.toLowerCase(); + var i = s.indexOf(sub); + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + function add(q, value) { + if (length > options.cacheLength){ + flush(); + } + if (!data[q]){ + length++; + } + data[q] = value; + } + + function populate(){ + if( !options.data ) return false; + // track the matches + var stMatchSets = {}, + nullData = 0; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( !options.url ) options.cacheLength = 1; + + // track all options for minChars = 0 + stMatchSets[""] = []; + + // loop through the array and create a lookup structure + for ( var i = 0, ol = options.data.length; i < ol; i++ ) { + var rawValue = options.data[i]; + // if rawValue is a string, make an array otherwise just reference the array + rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; + + var value = options.formatMatch(rawValue, i+1, options.data.length); + if ( value === false ) + continue; + + var firstChar = value.charAt(0).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[firstChar] ) + stMatchSets[firstChar] = []; + + // if the match is a string + var row = { + value: value, + data: rawValue, + result: options.formatResult && options.formatResult(rawValue) || value + }; + + // push the current match into the set list + stMatchSets[firstChar].push(row); + + // keep track of minChars zero items + if ( nullData++ < options.max ) { + stMatchSets[""].push(row); + } + }; + + // add the data items to the cache + $.each(stMatchSets, function(i, value) { + // increase the cache size + options.cacheLength++; + // add to the cache + add(i, value); + }); + } + + // populate any existing data + setTimeout(populate, 25); + + function flush(){ + data = {}; + length = 0; + } + + return { + flush: flush, + add: add, + populate: populate, + load: function(q) { + if (!options.cacheLength || !length) + return null; + + /* + * if dealing w/local data and matchContains than we must make sure + * to loop through all the data collections looking for matches + */ + if( !options.url && options.matchContains ){ + // track all matches + var csub = []; + // loop through all the data grids for matches + for( var k in data ){ + // don't search through the stMatchSets[""] (minChars: 0) cache + // this prevents duplicates + if( k.length > 0 ){ + var c = data[k]; + $.each(c, function(i, x) { + // if we've got a match, add it to the array + if (matchSubset(x.value, q)) { + csub.push(x); + } + }); + } + } + return csub; + } else + // if the exact item exists, use it + if (data[q]){ + return data[q]; + } else + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var c = data[q.substr(0, i)]; + if (c) { + var csub = []; + $.each(c, function(i, x) { + if ( (x.data.indexOf("#Header") == 0) || + (matchSubset(x.value, q)) ) { + csub[csub.length] = x; + } + }); + return csub; + } + } + + } + return null; + } + }; +}; + +$.Autocompleter.Select = function (options, input, select, config) { + var CLASSES = { + ACTIVE: "ac_over" + }; + + var listItems, + active = -1, + data, + term = "", + needsInit = true, + element, + list; + + // Create results + function init() { + if (!needsInit) + return; + element = $("<div/>") + .hide() + .addClass(options.resultsClass) + .css("position", "absolute") + .appendTo(document.body); + + list = $("<ul/>").appendTo(element).mouseover( function(event) { + if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { + active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); + // JG: Only add active class if target is not a header. + if (!headerAtPosition(active)) + $(target(event)).addClass(CLASSES.ACTIVE); + } + }).click(function(event) { + // JG: Ignore click on header. + active = $("li", list).index(target(event)); + if (headerAtPosition(active)) + return; + + // Handle click on autocomplete options. + $(target(event)).addClass(CLASSES.ACTIVE); + select(); + // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus + input.focus(); + return false; + }).mousedown(function() { + config.mouseDownOnSelect = true; + }).mouseup(function() { + config.mouseDownOnSelect = false; + }); + + if( options.width > 0 ) + element.css("width", options.width); + + needsInit = false; + } + + function target(event) { + var element = event.target; + while(element && element.tagName != "LI") + element = element.parentNode; + // more fun with IE, sometimes event.target is empty, just ignore it then + if(!element) + return []; + return element; + } + + // JG: Returns true iff there is a header element at the given position. + function headerAtPosition(position) + { + dataAtPosition = data[position].data; + return (dataAtPosition.indexOf("#Header") == 0); + } + + function moveSelect(step) { + listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); + // JG: while active item is a header, continue stepping. + var isHeader = false; + do + { + movePosition(step); + isHeader = headerAtPosition(active); + } + while (isHeader); + var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); + + + if(options.scroll) { + var offset = 0; + listItems.slice(0, active).each(function() { + offset += this.offsetHeight; + }); + if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { + list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); + } else if(offset < list.scrollTop()) { + list.scrollTop(offset); + } + } + }; + + function movePosition(step) { + active += step; + if (active < 0) { + active = listItems.size() - 1; + } else if (active >= listItems.size()) { + active = 0; + } + } + + function limitNumberOfItems(available) { + return options.max && options.max < available + ? options.max + : available; + } + + function fillList() { + list.empty(); + var max = limitNumberOfItems(data.length); + for (var i=0; i < max; i++) { + if (!data[i]) + continue; + var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term); + if ( formatted === false ) + continue; + + // JG: Build list item by formatting the item and choosing a CSS class. + if (headerAtPosition(i)) + { + // Found header element; only add header if there are subsequent elements. + if (i != max-1) + var li = $("<li/>").html(data[i].data[1]).addClass("ac_header").appendTo(list)[0]; + } + else + { + // Found completion element. + var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; + } + + $.data(li, "ac_data", data[i]); + } + listItems = list.find("li"); + if ( options.selectFirst ) { + listItems.slice(0, 1).addClass(CLASSES.ACTIVE); + active = 0; + } + // apply bgiframe if available + if ( $.fn.bgiframe ) + list.bgiframe(); + } + + return { + display: function(d, q) { + init(); + data = d; + term = q; + fillList(); + }, + next: function() { + moveSelect(1); + }, + prev: function() { + moveSelect(-1); + }, + pageUp: function() { + if (active != 0 && active - 8 < 0) { + moveSelect( -active ); + } else { + moveSelect(-8); + } + }, + pageDown: function() { + if (active != listItems.size() - 1 && active + 8 > listItems.size()) { + moveSelect( listItems.size() - 1 - active ); + } else { + moveSelect(8); + } + }, + hide: function() { + element && element.hide(); + listItems && listItems.removeClass(CLASSES.ACTIVE); + active = -1; + }, + visible : function() { + return element && element.is(":visible"); + }, + current: function() { + return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); + }, + show: function() { + var offset = $(input).offset(); + element.css({ + width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), + top: offset.top + input.offsetHeight, + left: offset.left + }).show(); + if(options.scroll) { + list.scrollTop(0); + list.css({ + maxHeight: options.scrollHeight, + overflow: 'auto' + }); + + if($.browser.msie && typeof document.body.style.maxHeight === "undefined") { + var listHeight = 0; + listItems.each(function() { + listHeight += this.offsetHeight; + }); + var scrollbarsVisible = listHeight > options.scrollHeight; + list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight ); + if (!scrollbarsVisible) { + // IE doesn't recalculate width when scrollbar disappears + listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) ); + } + } + + } + }, + selected: function() { + var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); + return selected && selected.length && $.data(selected[0], "ac_data"); + }, + emptyList: function (){ + list && list.empty(); + }, + unbind: function() { + element && element.remove(); + } + }; +}; + +$.Autocompleter.Selection = function(field, start, end) { + if( field.createTextRange ){ + var selRange = field.createTextRange(); + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } else if( field.setSelectionRange ){ + field.setSelectionRange(start, end); + } else { + if( field.selectionStart ){ + field.selectionStart = start; + field.selectionEnd = end; + } + } + field.focus(); +}; + +})(jQuery);
1
0
0
0
[hg] galaxy 2644: changes to the model to support tags
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/b6b4d07ad087
changeset: 2644:b6b4d07ad087 user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 15:35:27 2009 -0400 description: changes to the model to support tags 1 file(s) affected in this change: lib/galaxy/model/__init__.py diffs (41 lines): diff -r 1835c027763a -r b6b4d07ad087 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Fri Aug 28 15:31:06 2009 -0400 +++ b/lib/galaxy/model/__init__.py Fri Aug 28 15:35:27 2009 -0400 @@ -1142,6 +1142,37 @@ self.user = None self.title = None self.content = None + +class Tag ( object ): + def __init__( self, id=None, type=None, parent_id=None, name=None ): + self.id = id + self.type = type + self.parent_id = parent_id + self.name = name + + def __str__ ( self ): + return "Tag(id=%s, type=%s, parent_id=%s, name=%s)" % ( self.id, self.type, self.parent_id, self.name ) + +class ItemTagAssociation ( object ): + def __init__( self, item_id=None, tag_id=None, user_tname=None, value=None ): + self.item_id = item_id + self.tag_id = tag_id + self.user_tname = user_tname + self.value = None + self.user_value = None + + def __str__ ( self ): + return "%s(item_id=%s, item_tag=%s, user_tname=%s, value=%s, user_value=%s)" % (self.__class__.__name__, self.item_id, self.tag_id, self.user_tname, self.value. self.user_value ) + + +class HistoryTagAssociation ( ItemTagAssociation ): + pass + +class DatasetTagAssociation ( ItemTagAssociation ): + pass + +class HistoryDatasetAssociationTagAssociation ( ItemTagAssociation ): + pass
1
0
0
0
[hg] galaxy 2633: Migration script to handle mysql index error i...
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/b85cb0a65f46
changeset: 2633:b85cb0a65f46 user: jeremy goecks <jeremy.goecks(a)emory.edu> date: Fri Aug 28 13:13:18 2009 -0400 description: Migration script to handle mysql index error in previous migration script ( 0015_tagging.py ) 1 file(s) affected in this change: lib/galaxy/model/migrate/versions/0016_v0015_mysql_index_fix.py diffs (56 lines): diff -r 31150f0b216d -r b85cb0a65f46 lib/galaxy/model/migrate/versions/0016_v0015_mysql_index_fix.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/galaxy/model/migrate/versions/0016_v0015_mysql_index_fix.py Fri Aug 28 13:13:18 2009 -0400 @@ -0,0 +1,51 @@ +""" +This script fixes a problem introduced in 0015_tagging.py. MySQL has a name length +limit and thus the index "ix_hda_ta_history_dataset_association_id" has to be +manually created. +""" + +from sqlalchemy import * +from migrate import * + +import datetime +now = datetime.datetime.utcnow + +# Need our custom types, but don't import anything else from model +from galaxy.model.custom_types import * + +import logging +log = logging.getLogger( __name__ ) + +metadata = MetaData( migrate_engine ) + +def display_migration_details(): + print "" + print "This script fixes a problem introduced in 0015_tagging.py. MySQL has a" + print "name length limit and thus the index 'ix_hda_ta_history_dataset_association_id'" + print "has to be manually created." + +HistoryDatasetAssociationTagAssociation_table = Table( "history_dataset_association_tag_association", metadata, + Column( "history_dataset_association_id", Integer, ForeignKey( "history_dataset_association.id" ), index=True ), + Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ), + Column( "user_tname", TrimmedString(255), index=True), + Column( "value", TrimmedString(255), index=True), + Column( "user_value", TrimmedString(255), index=True) ) + +def upgrade(): + display_migration_details() + metadata.reflect() + i = Index( "ix_hda_ta_history_dataset_association_id", HistoryDatasetAssociationTagAssociation_table.c.history_dataset_association_id ) + try: + i.create() + except Exception, e: + print str(e) + log.debug( "Adding index 'ix_hdata_history_dataset_association_id' to table 'history_dataset_association_tag_association' table failed: %s" % str( e ) ) + +def downgrade(): + metadata.reflect() + i = Index( "ix_hda_ta_history_dataset_association_id", HistoryDatasetAssociationTagAssociation_table.c.history_dataset_association_id ) + try: + i.drop() + except Exception, e: + print str(e) + log.debug( "Removing index 'ix_hdata_history_dataset_association_id' to table 'history_dataset_association_tag_association' table failed: %s" % str( e ) ) \ No newline at end of file
1
0
0
0
[hg] galaxy 2634: Fix for unicode filenames in upload.
by Greg Von Kuster
29 Aug '09
29 Aug '09
details:
http://www.bx.psu.edu/hg/galaxy/rev/e87013fd0716
changeset: 2634:e87013fd0716 user: James Taylor <james(a)jamestaylor.org> date: Fri Aug 28 14:53:51 2009 -0400 description: Fix for unicode filenames in upload. 3 file(s) affected in this change: eggs.ini lib/galaxy/web/framework/__init__.py templates/root/history_common.mako diffs (55 lines): diff -r b85cb0a65f46 -r e87013fd0716 eggs.ini --- a/eggs.ini Fri Aug 28 13:13:18 2009 -0400 +++ b/eggs.ini Fri Aug 28 14:53:51 2009 -0400 @@ -32,7 +32,7 @@ flup = 0.5 lrucache = 0.2 ;lsprof - james -Mako = 0.1.10 +Mako = 0.2.4 MyghtyUtils = 0.52 nose = 0.9.1 NoseHTML = 0.2 @@ -81,7 +81,7 @@ elementtree =
http://effbot.org/downloads/elementtree-1.2.6-20050316.tar.gz
flup =
http://www.saddi.com/software/flup/dist/archive/flup-r2311.tar.gz
lrucache =
http://evan.prodromou.name/lrucache/lrucache-0.2.tar.gz
-Mako =
http://www.makotemplates.org/downloads/Mako-0.1.10.tar.gz
+Mako =
http://www.makotemplates.org/downloads/Mako-0.2.4.tar.gz
MyghtyUtils =
http://cheeseshop.python.org/packages/source/M/MyghtyUtils/MyghtyUtils-0.52…
nose =
http://www.somethingaboutorange.com/mrl/projects/nose/nose-0.9.1.tar.gz
NoseHTML =
http://dist.g2.bx.psu.edu/nosehtml-0.2.tar.bz2
diff -r b85cb0a65f46 -r e87013fd0716 lib/galaxy/web/framework/__init__.py --- a/lib/galaxy/web/framework/__init__.py Fri Aug 28 13:13:18 2009 -0400 +++ b/lib/galaxy/web/framework/__init__.py Fri Aug 28 14:53:51 2009 -0400 @@ -583,12 +583,12 @@ data.update( kwargs ) ## return template.render( **data ) def render( environ, start_response ): - response_write = start_response( self.response.wsgi_status(), - self.response.wsgi_headeritems() ) - class C: - def write( self, *args, **kwargs ): - response_write( *args, **kwargs ) - context = mako.runtime.Context( C(), **data ) + response_write = start_response( self.response.wsgi_status(), self.response.wsgi_headeritems() ) + class StreamBuffer( object ): + def write( self, d ): + response_write( d.encode( 'utf-8' ) ) + buffer = StreamBuffer() + context = mako.runtime.Context( buffer, **data ) template.render_context( context ) return [] return render diff -r b85cb0a65f46 -r e87013fd0716 templates/root/history_common.mako --- a/templates/root/history_common.mako Fri Aug 28 13:13:18 2009 -0400 +++ b/templates/root/history_common.mako Fri Aug 28 14:53:51 2009 -0400 @@ -35,7 +35,7 @@ <a class="icon-button delete" title="delete" href="${h.url_for( action='delete', id=data.id, show_deleted_on_refresh=show_deleted_on_refresh )}" id="historyItemDeleter-${data.id}"></a> </div> <span class="state-icon"></span> - <span class="historyItemTitle"><b>${hid}: ${data.display_name()}</b></span> + <span class="historyItemTitle"><b>${hid}: ${data.display_name().decode('utf-8')}</b></span> </div> ## Body for history items, extra info and actions, data "peek"
1
0
0
0
← Newer
1
2
3
4
5
...
16
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Results per page:
10
25
50
100
200