galaxy-dev
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
March 2010
- 36 participants
- 171 discussions
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/6d079d53f9db
changeset: 3530:6d079d53f9db
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon Mar 15 11:31:14 2010 -0400
description:
Add functionality for inline editing of dataset tags and annotation in history panel (icons are currently opposite save/rerun icons). Various style and template fixes as well.
diffstat:
lib/galaxy/web/base/controller.py | 11 +-
lib/galaxy/web/controllers/dataset.py | 31 ++++-
lib/galaxy/web/controllers/page.py | 2 +-
lib/galaxy/web/controllers/tag.py | 19 ++-
lib/galaxy/web/framework/helpers/grids.py | 4 +-
static/june_2007_style/autocomplete_tagging.css.tmpl | 5 +
static/june_2007_style/base.css.tmpl | 9 +-
static/june_2007_style/blue/autocomplete_tagging.css | 3 +-
static/june_2007_style/blue/base.css | 3 +-
templates/dataset/display.mako | 2 +-
templates/dataset/embed.mako | 6 +-
templates/display_base.mako | 2 +-
templates/embed_base.mako | 20 ++-
templates/grid_base_async.mako | 2 +-
templates/root/history.mako | 110 ++++++++++++++++--
templates/root/history_common.mako | 18 ++-
templates/tagging_common.mako | 6 +-
17 files changed, 203 insertions(+), 50 deletions(-)
diffs (553 lines):
diff -r 96ec861b4b6e -r 6d079d53f9db lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Sun Mar 14 11:49:44 2010 -0400
+++ b/lib/galaxy/web/base/controller.py Mon Mar 15 11:31:14 2010 -0400
@@ -62,7 +62,7 @@
def get_item_annotation_obj( self, db_session, user, item ):
""" Returns a user's annotation object for an item. """
- # Get annotation association. TODO: we could replace this eval() with a long if/else stmt, but this is more general without sacrificing
+ # Get annotation association.
try:
annotation_assoc_class = eval( "model.%sAnnotationAssociation" % item.__class__.__name__ )
except:
@@ -126,7 +126,7 @@
class UsesHistoryDatasetAssociation:
""" Mixin for controllers that use HistoryDatasetAssociation objects. """
- def get_dataset( self, trans, dataset_id, check_accessible=True ):
+ def get_dataset( self, trans, dataset_id, check_ownership=True, check_accessible=False ):
""" Get an HDA object by id. """
# DEPRECATION: We still support unencoded ids for backward compatibility
try:
@@ -136,6 +136,13 @@
data = trans.sa_session.query( model.HistoryDatasetAssociation ).get( dataset_id )
if not data:
raise paste.httpexceptions.HTTPRequestRangeNotSatisfiable( "Invalid dataset id: %s." % str( dataset_id ) )
+ if check_ownership:
+ # Verify ownership.
+ user = trans.get_user()
+ if not user:
+ error( "Must be logged in to manage Galaxy items" )
+ if data.history.user != user:
+ error( "%s is not owned by current user" % data.__class__.__name__ )
if check_accessible:
current_user_roles = trans.get_current_user_roles()
if trans.app.security_agent.can_access_dataset( current_user_roles, data.dataset ):
diff -r 96ec861b4b6e -r 6d079d53f9db lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Sun Mar 14 11:49:44 2010 -0400
+++ b/lib/galaxy/web/controllers/dataset.py Mon Mar 15 11:31:14 2010 -0400
@@ -5,6 +5,7 @@
from galaxy import util, datatypes, jobs, web, model
from cgi import escape, FieldStorage
from galaxy.datatypes.display_applications.util import encode_dataset_user, decode_dataset_user
+from galaxy.util.sanitize_html import sanitize_html
from email.MIMEText import MIMEText
import pkg_resources;
@@ -444,16 +445,14 @@
@web.require_login( "use Galaxy datasets" )
def get_name_and_link_async( self, trans, id=None ):
""" Returns dataset's name and link. """
- dataset = self.get_dataset( trans, id )
+ dataset = self.get_dataset( trans, id, False, True )
return_dict = { "name" : dataset.name, "link" : url_for( action="display_by_username_and_slug", username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) ) }
return return_dict
@web.expose
def get_embed_html_async( self, trans, id ):
""" Returns HTML for embedding a dataset in a page. """
-
- # TODO: user should be able to embed any item he has access to. see display_by_username_and_slug for security code.
- dataset = self.get_dataset( trans, id )
+ dataset = self.get_dataset( trans, id, False, True )
if dataset:
return "Embedded Dataset '%s'" % dataset.name
@@ -466,7 +465,7 @@
@web.expose
def display_by_username_and_slug( self, trans, username, slug, preview=True ):
""" Display dataset by username and slug; because datasets do not yet have slugs, the slug is the dataset's id. """
- dataset = self.get_dataset( trans, slug )
+ dataset = self.get_dataset( trans, slug, False, True )
if dataset:
truncated, dataset_data = self.get_data( dataset, preview )
dataset.annotation = self.get_item_annotation_str( trans.sa_session, dataset.history.user, dataset )
@@ -478,7 +477,7 @@
def get_item_content_async( self, trans, id ):
""" Returns item content in HTML format. """
- dataset = self.get_dataset( trans, id )
+ dataset = self.get_dataset( trans, id, False, True )
if dataset is None:
raise web.httpexceptions.HTTPNotFound()
truncated, dataset_data = self.get_data( dataset, preview=True )
@@ -486,6 +485,24 @@
dataset.annotation = self.get_item_annotation_str( trans.sa_session, trans.get_user(), dataset )
return trans.stream_template_mako( "/dataset/item_content.mako", item=dataset, item_data=dataset_data, truncated=truncated )
+ @web.expose
+ def annotate_async( self, trans, id, new_annotation=None, **kwargs ):
+ dataset = self.get_dataset( trans, id, False, True )
+ if not dataset:
+ web.httpexceptions.HTTPNotFound()
+ if dataset and new_annotation:
+ # Sanitize annotation before adding it.
+ new_annotation = sanitize_html( new_annotation, 'utf-8', 'text/html' )
+ self.add_item_annotation( trans, dataset, new_annotation )
+ trans.sa_session.flush()
+ return new_annotation
+
+ @web.expose
+ def get_annotation_async( self, trans, id ):
+ dataset = self.get_dataset( trans, id, False, True )
+ if not dataset:
+ web.httpexceptions.HTTPNotFound()
+ return self.get_item_annotation_str( trans.sa_session, trans.get_user(), dataset )
@web.expose
def display_at( self, trans, dataset_id, filename=None, **kwd ):
@@ -704,7 +721,7 @@
if user != history.user:
error_msg = error_msg + "You do not have permission to add datasets to %i requested histories. " % ( len( target_histories ) )
for dataset_id in dataset_ids:
- data = self.get_dataset( trans, dataset_id )
+ data = self.get_dataset( trans, dataset_id, False, True )
if data is None:
error_msg = error_msg + "You tried to copy a dataset that does not exist or that you do not have access to. "
invalid_datasets += 1
diff -r 96ec861b4b6e -r 6d079d53f9db lib/galaxy/web/controllers/page.py
--- a/lib/galaxy/web/controllers/page.py Sun Mar 14 11:49:44 2010 -0400
+++ b/lib/galaxy/web/controllers/page.py Mon Mar 15 11:31:14 2010 -0400
@@ -674,7 +674,7 @@
datasets = self.get_history_datasets( trans, history )
return trans.fill_template( "history/embed.mako", item=history, item_data=datasets )
elif item_class == model.HistoryDatasetAssociation:
- dataset = self.get_dataset( trans, item_id )
+ dataset = self.get_dataset( trans, item_id, False, True )
dataset.annotation = self.get_item_annotation_str( trans.sa_session, dataset.history.user, dataset )
if dataset:
data = self.get_data( dataset )
diff -r 96ec861b4b6e -r 6d079d53f9db lib/galaxy/web/controllers/tag.py
--- a/lib/galaxy/web/controllers/tag.py Sun Mar 14 11:49:44 2010 -0400
+++ b/lib/galaxy/web/controllers/tag.py Mon Mar 15 11:31:14 2010 -0400
@@ -11,12 +11,21 @@
def __init__(self, app):
BaseController.__init__(self, app)
-
- # Set up tag handler to recognize the following items: History, HistoryDatasetAssociation, Page, ...
self.tag_handler = TagHandler()
+
+ @web.expose
+ @web.require_login( "edit item tags" )
+ def get_tagging_elt_async( self, trans, item_id, item_class, elt_context="" ):
+ """ Returns HTML for editing an item's tags. """
+ item = self._get_item( trans, item_class, trans.security.decode_id( item_id ) )
+ if not item:
+ return trans.show_error_message( "No item of class %s with id % " % ( item_class, item_id ) )
+ user = trans.get_user()
+ return trans.fill_template( "/tagging_common.mako", tag_type="individual", user=trans.get_user(), tagged_item=item, elt_context=elt_context,
+ in_form=False, input_size="22", tag_click_fn="default_tag_click_fn", use_toggle_link=False )
@web.expose
- @web.require_login( "Add tag to an item." )
+ @web.require_login( "add tag to an item" )
def add_tag_async( self, trans, item_id=None, item_class=None, new_tag=None, context=None ):
""" Add tag to an item. """
@@ -28,10 +37,10 @@
# Log.
params = dict( item_id=item.id, item_class=item_class, tag=new_tag)
- trans.log_action( user, unicode( "tag"), context, params )
+ trans.log_action( user, unicode( "tag" ), context, params )
@web.expose
- @web.require_login( "Remove tag from an item." )
+ @web.require_login( "remove tag from an item" )
def remove_tag_async( self, trans, item_id=None, item_class=None, tag_name=None, context=None ):
""" Remove tag from an item. """
diff -r 96ec861b4b6e -r 6d079d53f9db lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Sun Mar 14 11:49:44 2010 -0400
+++ b/lib/galaxy/web/framework/helpers/grids.py Mon Mar 15 11:31:14 2010 -0400
@@ -389,7 +389,7 @@
self.grid_name = grid_name
def get_value( self, trans, grid, item ):
return trans.fill_template( "/tagging_common.mako", tag_type="community", trans=trans, user=trans.get_user(), tagged_item=item, elt_context=self.grid_name,
- in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter" )
+ in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter", use_toggle_link=True )
def filter( self, db_session, user, query, column_filter ):
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
if column_filter == "All":
@@ -418,7 +418,7 @@
""" Column that supports individual tags. """
def get_value( self, trans, grid, item ):
return trans.fill_template( "/tagging_common.mako", tag_type="individual", trans=trans, user=trans.get_user(), tagged_item=item, elt_context=self.grid_name,
- in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter" )
+ in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter", use_toggle_link=True )
def get_filter( self, user, column_filter ):
# Parse filter to extract multiple tags.
tag_handler = TagHandler()
diff -r 96ec861b4b6e -r 6d079d53f9db static/june_2007_style/autocomplete_tagging.css.tmpl
--- a/static/june_2007_style/autocomplete_tagging.css.tmpl Sun Mar 14 11:49:44 2010 -0400
+++ b/static/june_2007_style/autocomplete_tagging.css.tmpl Mon Mar 15 11:31:14 2010 -0400
@@ -74,6 +74,11 @@
cursor: pointer;
}
+.individual-tag-area:hover
+{
+ border:dotted #999999 1px;
+}
+
.active-tag-area {
background-color: white;
}
diff -r 96ec861b4b6e -r 6d079d53f9db static/june_2007_style/base.css.tmpl
--- a/static/june_2007_style/base.css.tmpl Sun Mar 14 11:49:44 2010 -0400
+++ b/static/june_2007_style/base.css.tmpl Mon Mar 15 11:31:14 2010 -0400
@@ -835,8 +835,7 @@
cursor:pointer;
}
-.editable-text:hover{
- background-image:url();
- background-repeat:no-repeat;
- background-position:right;
-}
+.editable-text:hover {
+ cursor: text;
+ border: dotted #999999 1px;
+}
\ No newline at end of file
diff -r 96ec861b4b6e -r 6d079d53f9db static/june_2007_style/blue/autocomplete_tagging.css
--- a/static/june_2007_style/blue/autocomplete_tagging.css Sun Mar 14 11:49:44 2010 -0400
+++ b/static/june_2007_style/blue/autocomplete_tagging.css Mon Mar 15 11:31:14 2010 -0400
@@ -7,7 +7,8 @@
.ac_over{background-color:#0A246A;color:white;}
.ac_header{font-style:normal;color:gray;border-bottom:0.1em solid gray;}
.tag-area{width:100%;}
-.individual-tag-area{border:solid 1px #eee;cursor:pointer;}
+.individual-tag-area{cursor:pointer;}
+.individual-tag-area:hover{border:dotted #999999 1px;}
.active-tag-area{background-color:white;}
.toggle-link{font-weight:normal;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:solid #bbb 1px;padding:0.1em 0.5em 0.1em 0.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;border-radius:.5em;background:#eee;}
diff -r 96ec861b4b6e -r 6d079d53f9db static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css Sun Mar 14 11:49:44 2010 -0400
+++ b/static/june_2007_style/blue/base.css Mon Mar 15 11:31:14 2010 -0400
@@ -145,4 +145,5 @@
.tipsy-east{background-position:right center;}
.tipsy-west{background-position:left center;}
.editable-text{cursor:pointer;}
-.editable-text:hover{background-image:url();background-repeat:no-repeat;background-position:right;}
+.editable-text:hover{cursor: text;border: dotted #999999 1px;}
+
diff -r 96ec861b4b6e -r 6d079d53f9db templates/dataset/display.mako
--- a/templates/dataset/display.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/dataset/display.mako Mon Mar 15 11:31:14 2010 -0400
@@ -22,7 +22,7 @@
</%def>
<%def name="render_item_links( data )">
- ## Provide links to save data and TODO: import dataset.
+ ## Provide links to save data and import dataset.
<a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( data.id ), to_ext=data.ext )}" class="icon-button disk tooltip" title="Save dataset"></a>
<a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( data.id ) )}" class="icon-button import tooltip" title="Import dataset"></a>
</%def>
diff -r 96ec861b4b6e -r 6d079d53f9db templates/dataset/embed.mako
--- a/templates/dataset/embed.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/dataset/embed.mako Mon Mar 15 11:31:14 2010 -0400
@@ -3,8 +3,12 @@
from galaxy.web.framework.helpers import iff
%>
-<%def name="render_item_specific_title_links( dataset )">
+<%def name="render_item_links( dataset )">
<a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ), to_ext=dataset.ext )}" title="Save dataset" class="icon-button disk tooltip"></a>
+ ## Links for importing and viewing an item.
+ <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( item.id ) )}" title="Import dataset" class="icon-button import tooltip"></a>
+ <a class="icon-button go-to-full-screen tooltip" href="${h.url_for( controller='/dataset', action='display_by_username_and_slug', username=dataset.history.user.username, slug=trans.security.encode_id( dataset.id ) )}" title="Go to dataset"></a>
+
</%def>
<%def name="render_summary_content( dataset, data )">
diff -r 96ec861b4b6e -r 6d079d53f9db templates/display_base.mako
--- a/templates/display_base.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/display_base.mako Mon Mar 15 11:31:14 2010 -0400
@@ -25,7 +25,7 @@
self.has_left_panel=False
self.has_right_panel=True
self.message_box_visible=False
- self.active_view="user"
+ self.active_view=""
self.overlay_visible=False
%>
</%def>
diff -r 96ec861b4b6e -r 6d079d53f9db templates/embed_base.mako
--- a/templates/embed_base.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/embed_base.mako Mon Mar 15 11:31:14 2010 -0400
@@ -18,8 +18,19 @@
</div>
</div>
-## Render item-specific title links.
-<%def name="render_item_specific_title_links( item )">
+## Render item links.
+<%def name="render_item_links( item )">
+ <%
+ item_display_name = get_class_display_name( item.__class__ ).lower()
+ item_controller = "/%s" % get_controller_name( item )
+ item_user = get_item_user( item )
+ item_slug = get_item_slug( item )
+ display_href = h.url_for( controller=item_controller, action='display_by_username_and_slug', username=item_user.username, slug=item_slug )
+ %>
+
+ ## Links for importing and viewing an item.
+ <a href="${h.url_for( controller=item_controller, action='imp', id=trans.security.encode_id( item.id ) )}" title="Import ${item_display_name}" class="icon-button import tooltip"></a>
+ <a class="icon-button go-to-full-screen tooltip" href="${display_href}" title="Go to ${item_display_name}"></a>
</%def>
<%def name="render_title( item )">
@@ -36,10 +47,7 @@
<a class="toggle-contract icon-button tooltip" href="${display_href}" title="Hide ${item_display_name} content"></a>
</div>
<div style="float: right">
- ${self.render_item_specific_title_links( item )}
- ## Links applicable for all items.
- <a href="${h.url_for( controller=item_controller, action='imp', id=trans.security.encode_id( item.id ) )}" title="Import ${item_display_name}" class="icon-button import tooltip"></a>
- <a class="icon-button go-to-full-screen tooltip" href="${display_href}" title="Go to ${item_display_name}"></a>
+ ${self.render_item_links( item )}
</div>
<h4><a class="toggle-embed tooltip" href="${display_href}" title="Show or hide ${item_display_name} content">Galaxy ${get_class_display_name( item.__class__ )} | ${get_item_name( item )}</a></h4>
%if hasattr( item, "annotation") and item.annotation:
diff -r 96ec861b4b6e -r 6d079d53f9db templates/grid_base_async.mako
--- a/templates/grid_base_async.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/grid_base_async.mako Mon Mar 15 11:31:14 2010 -0400
@@ -13,4 +13,4 @@
*****
${num_pages}
*****
-${render_message( grid )}
\ No newline at end of file
+${render_message( message, message_type )}
\ No newline at end of file
diff -r 96ec861b4b6e -r 6d079d53f9db templates/root/history.mako
--- a/templates/root/history.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/root/history.mako Mon Mar 15 11:31:14 2010 -0400
@@ -42,10 +42,10 @@
$.jStore.remove("history_expand_state");
}).show();
- // Rename management.
+ // History rename functionality.
async_save_text("history-name-container", "history-name", "${h.url_for( controller="/history", action="rename_async", id=trans.security.encode_id(history.id) )}", "new_name", 18);
- // Tag management.
+ // History tagging functionality.
var historyTagArea = $('#history-tag-area');
$('#history-tag').click( function()
{
@@ -57,7 +57,7 @@
return false;
});
- // Annotation management.
+ // History annotation functionality.
var historyAnnotationArea = $('#history-annotation-area');
$('#history-annotate').click( function() {
if ( historyAnnotationArea.is( ":hidden" ) ) {
@@ -104,7 +104,8 @@
})
}
}
-// Add show/hide link and delete link to a history item
+// (a) Add show/hide link and delete link to a history item;
+// (b) handle tagging and annotation using jquery.
function setupHistoryItem( query ) {
query.each( function() {
var id = this.id;
@@ -180,6 +181,99 @@
return false;
});
});
+
+ // Tag handling.
+ $(this).find( "a.icon-button.tags").each( function()
+ {
+ // Use links parameters but custom URL as ajax URL.
+ $(this).click( function() {
+ // Get tag area, tag element.
+ var history_item = $(this).parents(".historyItem");
+ var tag_area = history_item.find(".tag-area");
+ var tag_elt = history_item.find(".tag-elt");
+
+ // Show or hide tag area; if showing tag area and it's empty, fill it.
+ if ( tag_area.is( ":hidden" ) )
+ {
+ if (tag_elt.html() == "" )
+ {
+ // Need to fill tag element.
+ var href_parms = $(this).attr("href").split("?")[1];
+ var ajax_url = "${h.url_for( controller='tag', action='get_tagging_elt_async' )}?" + href_parms;
+ $.ajax({
+ url: ajax_url,
+ error: function() { alert( "Tagging failed" ) },
+ success: function(tag_elt_html) {
+ tag_elt.html(tag_elt_html);
+ tag_elt.find(".tooltip").tipsy( { gravity: 's' } );
+ tag_area.slideDown("fast");
+ }
+ });
+ }
+ else
+ {
+ // Tag element is filled; show.
+ tag_area.slideDown("fast");
+ }
+ }
+ else
+ {
+ // Hide.
+ tag_area.slideUp("fast");
+ }
+ return false;
+ });
+ });
+
+ // Annotation handling.
+ $(this).find( "a.icon-button.annotate").each( function()
+ {
+ // Use links parameters but custom URL as ajax URL.
+ $(this).click( function() {
+ // Get tag area, tag element.
+ var history_item = $(this).parents(".historyItem");
+ var annotation_area = history_item.find(".annotation-area");
+ var annotation_elt = history_item.find(".annotation-elt");
+
+ // Show or hide annotation area; if showing annotation area and it's empty, fill it.
+ if ( annotation_area.is( ":hidden" ) )
+ {
+ if (annotation_elt.html() == "" )
+ {
+ // Need to fill annotation element.
+ var href_parms = $(this).attr("href").split("?")[1];
+ var ajax_url = "${h.url_for( controller='dataset', action='get_annotation_async' )}?" + href_parms;
+ $.ajax({
+ url: ajax_url,
+ error: function() { alert( "Annotations failed" ) },
+ success: function(annotation) {
+ if (annotation == "")
+ annotation = "<i>Describe or add notes to dataset</i>";
+ annotation_elt.html(annotation);
+ annotation_area.find(".tooltip").tipsy( { gravity: 's' } );
+ async_save_text(
+ annotation_elt.attr("id"), annotation_elt.attr("id"),
+ "${h.url_for( controller="/dataset", action="annotate_async")}?" + href_parms,
+ "new_annotation", 18, true, 4);
+ annotation_area.slideDown("fast");
+ }
+ });
+ }
+ else
+ {
+ // Annotation element is filled; show.
+ annotation_area.slideDown("fast");
+ }
+ }
+ else
+ {
+ // Hide.
+ annotation_area.slideUp("fast");
+ }
+ return false;
+ });
+ });
+
});
};
// Looks for changes in dataset state using an async request. Keeps
@@ -279,13 +373,6 @@
padding: 3px;
margin: -4px;
}
-.editable-text:hover {
- cursor: text;
- border: dotted #999999 1px;
-}
-.tag-area {
- border: none;
-}
</style>
<noscript>
@@ -299,7 +386,6 @@
</head>
<body class="historyPage">
-
<div id="top-links" class="historyLinks">
<a title="${_('refresh')}" class="icon-button arrow-circle tooltip" href="${h.url_for('history', show_deleted=show_deleted)}"></a>
diff -r 96ec861b4b6e -r 6d079d53f9db templates/root/history_common.mako
--- a/templates/root/history_common.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/root/history_common.mako Mon Mar 15 11:31:14 2010 -0400
@@ -86,10 +86,26 @@
</div>
<div class="info">${_('Info: ')}${data.display_info()}</div>
<div>
+ <% dataset_id=trans.security.encode_id( data.id ) %>
%if data.has_data:
- <a href="${h.url_for( controller='dataset', action='display', dataset_id=trans.security.encode_id( data.id ), to_ext=data.ext )}" title="Save" class="icon-button disk tooltip"></a>
+ <a href="${h.url_for( controller='dataset', action='display', dataset_id=dataset_id, to_ext=data.ext )}" title="Save" class="icon-button disk tooltip"></a>
%if user_owns_dataset:
<a href="${h.url_for( controller='tool_runner', action='rerun', id=data.id )}" target="galaxy_main" title="Run this job again" class="icon-button arrow-circle tooltip"></a>
+ %if trans.user:
+ <div style="float: right">
+ <a href="${h.url_for( controller='tag', action='retag', item_class=data.__class__.__name__, item_id=dataset_id )}" target="galaxy_main" title="Edit dataset tags" class="icon-button tags tooltip"></a>
+ <a href="${h.url_for( controller='dataset', action='annotate', id=dataset_id )}" target="galaxy_main" title="Edit dataset annotation" class="icon-button annotate tooltip"></a>
+ </div>
+ <div style="clear: both"></div>
+ <div class="tag-area" style="display: none">
+ <strong>Tags:</strong>
+ <div class="tag-elt"></div>
+ </div>
+ <div id="${dataset_id}-annotation-area" class="annotation-area" style="display: none">
+ <strong>Annotation:</strong>
+ <div id="${dataset_id}-annotation-elt" style="margin: 1px 0px 1px 0px" class="annotation-elt tooltip editable-text" title="Edit dataset annotation"></div>
+ </div>
+ %endif
%endif
<div style="clear: both"></div>
%for display_app in data.datatype.get_display_types():
diff -r 96ec861b4b6e -r 6d079d53f9db templates/tagging_common.mako
--- a/templates/tagging_common.mako Sun Mar 14 11:49:44 2010 -0400
+++ b/templates/tagging_common.mako Mon Mar 15 11:31:14 2010 -0400
@@ -13,7 +13,7 @@
## Render a tagging element if there is a tagged_item.
%if tagged_item is not None:
%if tag_type == "individual":
- ${render_individual_tagging_element(user=user, tagged_item=tagged_item, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn)}
+ ${render_individual_tagging_element( user=user, tagged_item=tagged_item, elt_context=elt_context, in_form=in_form, input_size=input_size, tag_click_fn=tag_click_fn, use_toggle_link=use_toggle_link )}
%elif tag_type == "community":
${render_community_tagging_element(tagged_item=tagged_item, elt_context=elt_context, tag_click_fn=tag_click_fn)}
%endif
@@ -123,7 +123,7 @@
//
// Set up autocomplete tagger.
//
-
+
//
// Default function get text to display on the toggle link.
//
@@ -193,7 +193,7 @@
ajax_delete_tag_url: "${h.url_for( controller='/tag', action='remove_tag_async', item_id=tagged_item_id, item_class=tagged_item.__class__.__name__, context=elt_context )}",
delete_tag_img: "${h.url_for('/static/images/delete_tag_icon_gray.png')}",
delete_tag_img_rollover: "${h.url_for('/static/images/delete_tag_icon_white.png')}",
- use_toggle_link: ${iff( use_toggle_link, 'true', 'false' )},
+ use_toggle_link: ${iff( use_toggle_link, 'true', 'false' )}
};
$('#${elt_id}').autocomplete_tagging(options);
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/96ec861b4b6e
changeset: 3529:96ec861b4b6e
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Sun Mar 14 11:49:44 2010 -0400
description:
Make the login/register/logout sequence more user friendly. Specific changes: (a) use panels so that Galaxy masthead is always available; (b) provide links to guide users past login; (c) enable 'user' to be an active view; (d) updated functional tests.
diffstat:
lib/galaxy/web/controllers/dataset.py | 4 +-
lib/galaxy/web/controllers/user.py | 28 ++-
lib/galaxy/web/controllers/visualization.py | 2 +-
lib/galaxy/web/controllers/workflow.py | 8 +-
lib/galaxy/web/framework/__init__.py | 26 +-
templates/base_panels.mako | 14 +-
templates/display_base.mako | 12 +-
templates/form.mako | 115 ++++++++++------
templates/history/list_published.mako | 2 +-
templates/message.mako | 3 +-
templates/page/list_published.mako | 2 +-
templates/user/register.mako | 162 ++++++++++++----------
templates/visualization/list_published.mako | 2 +-
templates/workflow/list.mako | 193 +++++++++++++++------------
templates/workflow/list_published.mako | 2 +-
test/base/twilltestcase.py | 11 +-
16 files changed, 329 insertions(+), 257 deletions(-)
diffs (900 lines):
diff -r 48e83411aa91 -r 96ec861b4b6e lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Fri Mar 12 16:11:26 2010 -0500
+++ b/lib/galaxy/web/controllers/dataset.py Sun Mar 14 11:49:44 2010 -0400
@@ -436,8 +436,8 @@
# Do import.
cur_history = trans.get_history( create=True )
status, message = self._copy_datasets( trans, [ dataset_id ], [ cur_history ] )
- message = message + "<br>You can <a href='%s'>start using the dataset</a> or %s." % ( url_for('/'), referer_message )
- return trans.show_message( message, type=status )
+ message = "Dataset imported. <br>You can <a href='%s'>start using the dataset</a> or %s." % ( url_for('/'), referer_message )
+ return trans.show_message( message, type=status, use_panels=True )
@web.expose
@web.json
diff -r 48e83411aa91 -r 96ec861b4b6e lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py Fri Mar 12 16:11:26 2010 -0500
+++ b/lib/galaxy/web/controllers/user.py Sun Mar 14 11:49:44 2010 -0400
@@ -115,9 +115,14 @@
you share publicly. Usernames must be at least
four characters in length and contain only lowercase
letters, numbers, and the '-' character.""" ) )
+
@web.expose
- def login( self, trans, email='', password='' ):
+ def login( self, trans, email='', password='', referer='', use_panels='True' ):
email_error = password_error = None
+
+ # Convert use_panels to Boolean.
+ use_panels = use_panels in [ 'True', 'true', 't', 'T' ]
+
# Attempt login
if trans.app.config.require_login:
refresh_frames = [ 'masthead', 'history', 'tools' ]
@@ -136,21 +141,23 @@
else:
trans.handle_user_login( user )
trans.log_event( "User logged in" )
- msg = "Now logged in as " + user.email + "."
+ msg = "You are now logged in as %s.<br>You can <a href='%s'>go back to the page you were visiting</a> or <a href='%s'>go to the Galaxy homepage</a>." % ( user.email, referer, url_for( '/' ) )
if trans.app.config.require_login:
msg += ' <a href="%s">Click here</a> to continue to the front page.' % web.url_for( '/static/welcome.html' )
- return trans.show_ok_message( msg, refresh_frames=refresh_frames )
+ return trans.show_ok_message( msg, refresh_frames=refresh_frames, use_panels=use_panels, active_view="user" )
form = web.FormBuilder( web.url_for(), "Login", submit_text="Login" ) \
.add_text( "email", "Email address", value=email, error=email_error ) \
.add_password( "password", "Password", value='', error=password_error,
- help="<a href='%s'>Forgot password? Reset here</a>" % web.url_for( action='reset_password' ) )
+ help="<a href='%s'>Forgot password? Reset here</a>" % web.url_for( action='reset_password' ) ) \
+ .add_input( "hidden", "referer", "referer", value=trans.request.referer, use_label=False )
if trans.app.config.require_login:
if trans.app.config.allow_user_creation:
- return trans.show_form( form, header = require_login_creation_template % web.url_for( action = 'create' ) )
+ return trans.show_form( form, header = require_login_creation_template % web.url_for( action = 'create' ), use_panels=use_panels, active_view="user" )
else:
- return trans.show_form( form, header = require_login_nocreation_template )
+ return trans.show_form( form, header = require_login_nocreation_template, use_panels=use_panels, active_view="user" )
else:
- return trans.show_form( form )
+ return trans.show_form( form, use_panels=use_panels, active_view="user" )
+
@web.expose
def logout( self, trans ):
if trans.app.config.require_login:
@@ -160,10 +167,11 @@
# Since logging an event requires a session, we'll log prior to ending the session
trans.log_event( "User logged out" )
trans.handle_user_logout()
- msg = "You are no longer logged in."
+ msg = "You have been logged out.<br>You can <a href='%s'>go back to the page you were visiting</a> or <a href='%s'>go to the Galaxy homepage</a>." % ( trans.request.referer, url_for( '/' ) )
if trans.app.config.require_login:
msg += ' <a href="%s">Click here</a> to return to the login page.' % web.url_for( controller='user', action='login' )
- return trans.show_ok_message( msg, refresh_frames=refresh_frames )
+ return trans.show_ok_message( msg, refresh_frames=refresh_frames, use_panels=True, active_view="user" )
+
@web.expose
def create( self, trans, **kwd ):
params = util.Params( kwd )
@@ -217,7 +225,7 @@
trans.log_event( "User created a new account" )
trans.log_event( "User logged in" )
# subscribe user to email list
- return trans.show_ok_message( "Now logged in as " + user.email, refresh_frames=refresh_frames )
+ return trans.show_ok_message( "Now logged in as %s.<br><a href='%s'>Return to the Galaxy start page.</a>" % ( user.email, url_for( '/' ) ), refresh_frames=refresh_frames, use_panels=True )
else:
trans.response.send_redirect( web.url_for( controller='admin',
action='users',
diff -r 48e83411aa91 -r 96ec861b4b6e lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py Fri Mar 12 16:11:26 2010 -0500
+++ b/lib/galaxy/web/controllers/visualization.py Sun Mar 14 11:49:44 2010 -0400
@@ -75,7 +75,7 @@
return trans.fill_template( "visualization/list_published.mako", grid=grid )
@web.expose
- @web.require_login("use Galaxy visualizations")
+ @web.require_login( "use Galaxy visualizations", use_panels=True )
def list( self, trans, *args, **kwargs ):
# Handle operation
if 'operation' in kwargs and 'id' in kwargs:
diff -r 48e83411aa91 -r 96ec861b4b6e lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Fri Mar 12 16:11:26 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Sun Mar 14 11:49:44 2010 -0400
@@ -85,7 +85,7 @@
@web.expose
def index( self, trans ):
- return trans.fill_template( "workflow/index.mako" )
+ return self.list( trans )
@web.expose
@web.require_login( "use Galaxy workflows" )
@@ -102,7 +102,7 @@
return self.stored_list_grid( trans, **kwargs )
@web.expose
- @web.require_login( "use Galaxy workflows" )
+ @web.require_login( "use Galaxy workflows", use_panels=True )
def list( self, trans ):
"""
Render workflow main page (management of existing workflows)
@@ -276,7 +276,7 @@
item=stored )
@web.expose
- @web.require_login( "use Galaxy workflows" )
+ @web.require_login( "to import a workflow", use_panels=True )
def imp( self, trans, id, **kwargs ):
# Set referer message.
referer = trans.request.referer
@@ -284,7 +284,7 @@
referer_message = "<a href='%s'>return to the previous page</a>" % referer
else:
referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
-
+
# Do import.
session = trans.sa_session
stored = self.get_stored_workflow( trans, id, check_ownership=False )
diff -r 48e83411aa91 -r 96ec861b4b6e lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Fri Mar 12 16:11:26 2010 -0500
+++ b/lib/galaxy/web/framework/__init__.py Sun Mar 14 11:49:44 2010 -0400
@@ -65,15 +65,15 @@
decorator.exposed = True
return decorator
-def require_login( verb="perform this action" ):
+def require_login( verb="perform this action", use_panels=False ):
def argcatcher( func ):
def decorator( self, trans, *args, **kwargs ):
if trans.get_user():
return func( self, trans, *args, **kwargs )
else:
return trans.show_error_message(
- "You must be <a target='galaxy_main' href='%s'>logged in</a> to %s</div>"
- % ( url_for( controller='user', action='login' ), verb ) )
+ "You must be <a target='_top' href='%s'>logged in</a> to %s</div>."
+ % ( url_for( controller='user', action='login' ), verb ), use_panels=use_panels )
return decorator
return argcatcher
@@ -561,7 +561,7 @@
context.
"""
return self.template_context['message']
- def show_message( self, message, type='info', refresh_frames=[], cont=None, use_panels=False ):
+ def show_message( self, message, type='info', refresh_frames=[], cont=None, use_panels=False, active_view="" ):
"""
Convenience method for displaying a simple page with a single message.
@@ -571,28 +571,28 @@
`refresh_frames`: names of frames in the interface that should be
refreshed when the message is displayed
"""
- return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels )
- def show_error_message( self, message, refresh_frames=[], use_panels=False ):
+ return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels, active_view=active_view )
+ def show_error_message( self, message, refresh_frames=[], use_panels=False, active_view="" ):
"""
Convenience method for displaying an error message. See `show_message`.
"""
- return self.show_message( message, 'error', refresh_frames, use_panels=use_panels )
- def show_ok_message( self, message, refresh_frames=[], use_panels=False ):
+ return self.show_message( message, 'error', refresh_frames, use_panels=use_panels, active_view=active_view )
+ def show_ok_message( self, message, refresh_frames=[], use_panels=False, active_view="" ):
"""
Convenience method for displaying an ok message. See `show_message`.
"""
- return self.show_message( message, 'done', refresh_frames, use_panels=use_panels )
- def show_warn_message( self, message, refresh_frames=[], use_panels=False ):
+ return self.show_message( message, 'done', refresh_frames, use_panels=use_panels, active_view=active_view )
+ def show_warn_message( self, message, refresh_frames=[], use_panels=False, active_view="" ):
"""
Convenience method for displaying an warn message. See `show_message`.
"""
- return self.show_message( message, 'warning', refresh_frames, use_panels=use_panels )
- def show_form( self, form, header=None, template="form.mako" ):
+ return self.show_message( message, 'warning', refresh_frames, use_panels=use_panels, active_view=active_view )
+ def show_form( self, form, header=None, template="form.mako", use_panels=False, active_view="" ):
"""
Convenience method for displaying a simple page with a single HTML
form.
"""
- return self.fill_template( template, form=form, header=header )
+ return self.fill_template( template, form=form, header=header, use_panels=use_panels, active_view=active_view )
def fill_template(self, filename, **kwargs):
"""
Fill in a template, putting any keyword arguments on the context.
diff -r 48e83411aa91 -r 96ec861b4b6e templates/base_panels.mako
--- a/templates/base_panels.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/base_panels.mako Sun Mar 14 11:49:44 2010 -0400
@@ -227,7 +227,13 @@
</div>
</td>
- <td class="tab">
+ ## User tab.
+ <%
+ cls = "tab"
+ if self.active_view == 'user':
+ cls += " active"
+ %>
+ <td class="${cls}">
<a>User</a>
<%
if trans.user:
@@ -241,9 +247,9 @@
%>
<div class="submenu">
<ul class="loggedout-only" style="${style1}">
- <li><a target="galaxy_main" href="${h.url_for( controller='/user', action='login' )}">Login</a></li>
+ <li><a href="${h.url_for( controller='/user', action='login' )}">Login</a></li>
%if app.config.allow_user_creation:
- <li><a target="galaxy_main" href="${h.url_for( controller='/user', action='create' )}">Register</a></li>
+ <li><a href="${h.url_for( controller='/user', action='create' )}">Register</a></li>
%endif
</ul>
<ul class="loggedin-only" style="${style2}">
@@ -259,7 +265,7 @@
logout_target = ""
logout_url = h.url_for( controller='/root', action='index', m_c='user', m_a='logout' )
else:
- logout_target = "galaxy_main"
+ logout_target = ""
logout_url = h.url_for( controller='/user', action='logout' )
%>
<li><a target="${logout_target}" href="${logout_url}">Logout</a></li>
diff -r 48e83411aa91 -r 96ec861b4b6e templates/display_base.mako
--- a/templates/display_base.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/display_base.mako Sun Mar 14 11:49:44 2010 -0400
@@ -216,11 +216,13 @@
%endif
</div>
## Individual tags.
- <p>
- <div>
- Yours:
- ${render_individual_tagging_element( user=trans.get_user(), tagged_item=item, elt_context='view.mako', use_toggle_link=False, tag_click_fn='community_tag_click' )}
- </div>
+ %if trans.get_user():
+ <p>
+ <div>
+ Yours:
+ ${render_individual_tagging_element( user=trans.get_user(), tagged_item=item, elt_context='view.mako', use_toggle_link=False, tag_click_fn='community_tag_click' )}
+ </div>
+ %endif
</div>
</div>
</div>
diff -r 48e83411aa91 -r 96ec861b4b6e templates/form.mako
--- a/templates/form.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/form.mako Sun Mar 14 11:49:44 2010 -0400
@@ -1,54 +1,83 @@
+<%!
+ def inherit(context):
+ if context.get('use_panels') is True:
+ print "here"
+ return '/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
<% _=n_ %>
-<%inherit file="/base.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view=active_view
+ self.message_box_visible=False
+%>
+</%def>
+
+
<%def name="title()">${form.title}</%def>
<%def name="javascripts()">
-${parent.javascripts()}
-<script type="text/javascript">
-$(function(){
- $("input:text:first").focus();
-})
-</script>
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ $(function(){
+ $("input:text:first").focus();
+ })
+ </script>
</%def>
-%if header:
- ${header}
-%endif
+<%def name="center_panel()">
+ ${render_form( )}
+</%def>
-<div class="form">
- <div class="form-title">${form.title}</div>
- <div class="form-body">
- <form name="${form.name}" action="${form.action}" method="post" >
- %for input in form.inputs:
- <%
- cls = "form-row"
- if input.error:
- cls += " form-row-error"
- %>
- <div class="${cls}">
- %if input.use_label:
- <label>
- ${_(input.label)}:
- </label>
- %endif
- <div class="form-row-input">
- <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
- </div>
- %if input.error:
- <div class="form-row-error-message">${input.error}</div>
- %endif
- %if input.help:
- <div class="toolParamHelp" style="clear: both;">
- ${input.help}
- </div>
- %endif
+<%def name="body()">
+ ${render_form( )}
+</%def>
+
+<%def name="render_form()">
+ %if header:
+ ${header}
+ %endif
- <div style="clear: both"></div>
+ <div class="form" style="margin: 1em">
+ <div class="form-title">${form.title}</div>
+ <div class="form-body">
+ <form name="${form.name}" action="${form.action}" method="post" >
+ %for input in form.inputs:
+ <%
+ cls = "form-row"
+ if input.error:
+ cls += " form-row-error"
+ %>
+ <div class="${cls}">
+ %if input.use_label:
+ <label>
+ ${_(input.label)}:
+ </label>
+ %endif
+ <div class="form-row-input">
+ <input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
+ </div>
+ %if input.error:
+ <div class="form-row-error-message">${input.error}</div>
+ %endif
+ %if input.help:
+ <div class="toolParamHelp" style="clear: both;">
+ ${input.help}
+ </div>
+ %endif
- </div>
- %endfor
- <div class="form-row"><input type="submit" value="${form.submit_text}"></div>
+ <div style="clear: both"></div>
- </form>
+ </div>
+ %endfor
+ <div class="form-row"><input type="submit" value="${form.submit_text}"></div>
+
+ </form>
+ </div>
</div>
-</div>
+</%def>
\ No newline at end of file
diff -r 48e83411aa91 -r 96ec861b4b6e templates/history/list_published.mako
--- a/templates/history/list_published.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/history/list_published.mako Sun Mar 14 11:49:44 2010 -0400
@@ -10,7 +10,7 @@
</%def>
<%def name="title()">
- Galaxy :: Published Histories
+ Galaxy | Published Histories
</%def>
<%def name="stylesheets()">
diff -r 48e83411aa91 -r 96ec861b4b6e templates/message.mako
--- a/templates/message.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/message.mako Sun Mar 14 11:49:44 2010 -0400
@@ -1,6 +1,6 @@
<%!
def inherit(context):
- if context.get('use_panels'):
+ if context.get('use_panels') is True:
return '/base_panels.mako'
else:
return '/base.mako'
@@ -69,7 +69,6 @@
${render_large_message( message, message_type )}
</%def>
-## Render the grid's basic elements. Each of these elements can be subclassed.
<%def name="body()">
${render_large_message( message, message_type )}
</%def>
diff -r 48e83411aa91 -r 96ec861b4b6e templates/page/list_published.mako
--- a/templates/page/list_published.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/page/list_published.mako Sun Mar 14 11:49:44 2010 -0400
@@ -10,7 +10,7 @@
</%def>
<%def name="title()">
- Galaxy :: Published Pages
+ Galaxy | Published Pages
</%def>
<%def name="stylesheets()">
diff -r 48e83411aa91 -r 96ec861b4b6e templates/user/register.mako
--- a/templates/user/register.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/user/register.mako Sun Mar 14 11:49:44 2010 -0400
@@ -1,87 +1,99 @@
-<%inherit file="/base.mako"/>
+<%inherit file="/base_panels.mako"/>
<%namespace file="/message.mako" import="render_msg" />
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="user"
+ self.message_box_visible=False
+%>
+</%def>
-%if msg:
- ${render_msg( msg, messagetype )}
-%endif
-
-
-
-<script type="text/javascript">
-$( function() {
- $( "select[refresh_on_change='true']").change( function() {
- var refresh = false;
- var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
- if ( refresh_on_change_values ) {
- refresh_on_change_values = refresh_on_change_values.value.split( ',' );
- var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
- for( i= 0; i < refresh_on_change_values.length; i++ ) {
- if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
- refresh = true;
- break;
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ $( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ var refresh = false;
+ var refresh_on_change_values = $( this )[0].attributes.getNamedItem( 'refresh_on_change_values' )
+ if ( refresh_on_change_values ) {
+ refresh_on_change_values = refresh_on_change_values.value.split( ',' );
+ var last_selected_value = $( this )[0].attributes.getNamedItem( 'last_selected_value' );
+ for( i= 0; i < refresh_on_change_values.length; i++ ) {
+ if ( $( this )[0].value == refresh_on_change_values[i] || ( last_selected_value && last_selected_value.value == refresh_on_change_values[i] ) ){
+ refresh = true;
+ break;
+ }
}
}
- }
- else {
- refresh = true;
- }
- if ( refresh ){
- $( "#registration" ).submit();
- }
+ else {
+ refresh = true;
+ }
+ if ( refresh ){
+ $( "#registration" ).submit();
+ }
+ });
});
-});
-</script>
+ </script>
-<div class="toolForm">
- <form name="registration" id="registration" action="${h.url_for( controller='user', action='create', admin_view=admin_view )}" method="post" >
- <div class="toolFormTitle">Create account</div>
- <div class="form-row">
- <label>Email</label>
- ${login_info[ 'Email' ].get_html()}
- </div>
- <div class="form-row">
- <label>Password</label>
- ${login_info[ 'Password' ].get_html()}
- </div>
- <div class="form-row">
- <label>Confirm</label>
- ${login_info[ 'Confirm' ].get_html()}
- </div>
- <div class="form-row">
- <label>Public Username</label>
- ${login_info[ 'Public Username' ].get_html()}
- <div class="toolParamHelp" style="clear: both;">
- Optional
+</%def>
+
+<%def name="center_panel()">
+ %if msg:
+ ${render_msg( msg, messagetype )}
+ %endif
+
+ <div class="toolForm" style="margin: 1em">
+ <form name="registration" id="registration" action="${h.url_for( controller='user', action='create', admin_view=admin_view )}" method="post" >
+ <div class="toolFormTitle">Create account</div>
+ <div class="form-row">
+ <label>Email</label>
+ ${login_info[ 'Email' ].get_html()}
</div>
- </div>
- <div class="form-row">
- <label>Subscribe To Mailing List</label>
- ${login_info[ 'Subscribe To Mailing List' ].get_html()}
- </div>
- %if user_info_select:
<div class="form-row">
- <label>User type</label>
- ${user_info_select.get_html()}
+ <label>Password</label>
+ ${login_info[ 'Password' ].get_html()}
</div>
- %endif
- %if user_info_form:
- %for field in widgets:
+ <div class="form-row">
+ <label>Confirm Password</label>
+ ${login_info[ 'Confirm' ].get_html()}
+ </div>
+ <div class="form-row">
+ <label>Public Username</label>
+ ${login_info[ 'Public Username' ].get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ When you share or publish items, this name is shown as the author.
+ </div>
+ </div>
+ <div class="form-row">
+ <label>Subscribe To Mailing List</label>
+ ${login_info[ 'Subscribe To Mailing List' ].get_html()}
+ </div>
+ %if user_info_select:
<div class="form-row">
- <label>${field['label']}</label>
- ${field['widget'].get_html()}
- <div class="toolParamHelp" style="clear: both;">
- ${field['helptext']}
+ <label>User type</label>
+ ${user_info_select.get_html()}
+ </div>
+ %endif
+ %if user_info_form:
+ %for field in widgets:
+ <div class="form-row">
+ <label>${field['label']}</label>
+ ${field['widget'].get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ ${field['helptext']}
+ </div>
+ <div style="clear: both"></div>
</div>
- <div style="clear: both"></div>
- </div>
- %endfor
- %if not user_info_select:
- <input type="hidden" name="user_info_select" value="${user_info_form.id}"/>
- %endif
- %endif
- <div class="form-row">
- <input type="submit" name="create_user_button" value="Submit">
- </div>
- </form>
-</div>
\ No newline at end of file
+ %endfor
+ %if not user_info_select:
+ <input type="hidden" name="user_info_select" value="${user_info_form.id}"/>
+ %endif
+ %endif
+ <div class="form-row">
+ <input type="submit" name="create_user_button" value="Submit">
+ </div>
+ </form>
+ </div>
+</%def>
\ No newline at end of file
diff -r 48e83411aa91 -r 96ec861b4b6e templates/visualization/list_published.mako
--- a/templates/visualization/list_published.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/visualization/list_published.mako Sun Mar 14 11:49:44 2010 -0400
@@ -10,7 +10,7 @@
</%def>
<%def name="title()">
- Galaxy :: Published Visualizations
+ Galaxy | Published Visualizations
</%def>
<%def name="stylesheets()">
diff -r 48e83411aa91 -r 96ec861b4b6e templates/workflow/list.mako
--- a/templates/workflow/list.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/workflow/list.mako Sun Mar 14 11:49:44 2010 -0400
@@ -1,103 +1,118 @@
-<%inherit file="/base.mako"/>
+<%inherit file="/base_panels.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="workflow"
+ self.message_box_visible=False
+%>
+</%def>
<%def name="title()">Workflow home</%def>
-%if message:
-<%
- try:
- messagetype
- except:
- messagetype = "done"
-%>
-<p />
-<div class="${messagetype}message">
- ${message}
-</div>
-%endif
+<%def name="center_panel()">
+ <div style="overflow: auto; height: 100%;">
+ <div class="page-container" style="padding: 10px;">
+ %if message:
+ <%
+ try:
+ messagetype
+ except:
+ messagetype = "done"
+ %>
+ <p />
+ <div class="${messagetype}message">
+ ${message}
+ </div>
+ %endif
-<h2>Your workflows</h2>
+ <h2>Your workflows</h2>
-<ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( action='create' )}">
- <img src="${h.url_for('/static/images/silk/add.png')}" />
- <span>Create new workflow</span>
- </a>
- </li>
-</ul>
+ <ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( action='create' )}">
+ <img src="${h.url_for('/static/images/silk/add.png')}" />
+ <span>Create new workflow</span>
+ </a>
+ </li>
+ </ul>
-%if workflows:
- <table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" style="width:100%;">
- <tr class="header">
- <th>Name</th>
- <th># of Steps</th>
- ## <th>Last Updated</th>
- <th></th>
- </tr>
- %for i, workflow in enumerate( workflows ):
- <tr>
- <td>
- <div class="menubutton" style="float: left;" id="wf-${i}-popup">
- ${workflow.name | h}
- </div>
- </td>
- <td>${len(workflow.latest_workflow.steps)}</td>
- ## <td>${str(workflow.update_time)[:19]}</td>
- <td>
- <div popupmenu="wf-${i}-popup">
- <a class="action-button" href="${h.url_for( action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">Edit</a>
- <a class="action-button" href="${h.url_for( controller='root', action='index', workflow_id=trans.security.encode_id(workflow.id) )}" target="_parent">Run</a>
- <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id(workflow.id) )}">Share or Publish</a>
- <a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
- <a class="action-button" href="${h.url_for( action='rename', id=trans.security.encode_id(workflow.id) )}">Rename</a>
- <a class="action-button" confirm="Are you sure you want to delete workflow '${workflow.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(workflow.id) )}">Delete</a>
- </div>
- </td>
- </tr>
- %endfor
- </table>
-%else:
+ %if workflows:
+ <table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" style="width:100%;">
+ <tr class="header">
+ <th>Name</th>
+ <th># of Steps</th>
+ ## <th>Last Updated</th>
+ <th></th>
+ </tr>
+ %for i, workflow in enumerate( workflows ):
+ <tr>
+ <td>
+ <div class="menubutton" style="float: left;" id="wf-${i}-popup">
+ ${workflow.name | h}
+ </div>
+ </td>
+ <td>${len(workflow.latest_workflow.steps)}</td>
+ ## <td>${str(workflow.update_time)[:19]}</td>
+ <td>
+ <div popupmenu="wf-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='editor', id=trans.security.encode_id(workflow.id) )}" target="_parent">Edit</a>
+ <a class="action-button" href="${h.url_for( controller='root', action='index', workflow_id=trans.security.encode_id(workflow.id) )}" target="_parent">Run</a>
+ <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id(workflow.id) )}">Share or Publish</a>
+ <a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
+ <a class="action-button" href="${h.url_for( action='rename', id=trans.security.encode_id(workflow.id) )}">Rename</a>
+ <a class="action-button" confirm="Are you sure you want to delete workflow '${workflow.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(workflow.id) )}">Delete</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
- You have no workflows.
+ You have no workflows.
-%endif
+ %endif
-<h2>Workflows shared with you by others</h2>
+ <h2>Workflows shared with you by others</h2>
-%if shared_by_others:
- <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr class="header">
- <th>Name</th>
- <th>Owner</th>
- <th># of Steps</th>
- <th></th>
- </tr>
- %for i, association in enumerate( shared_by_others ):
- <% workflow = association.stored_workflow %>
- <tr>
- <td>
- <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name | h}</a>
- </td>
- <td>${workflow.user.email}</td>
- <td>${len(workflow.latest_workflow.steps)}</td>
- <td>
- <div popupmenu="shared-${i}-popup">
- <a class="action-button" href="${h.url_for( action='display_by_username_and_slug', username=workflow.user.username, slug=workflow.slug)}" target="_top">View</a>
- <a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
- <a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
- </div>
- </td>
- </tr>
- %endfor
- </table>
-%else:
+ %if shared_by_others:
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>Name</th>
+ <th>Owner</th>
+ <th># of Steps</th>
+ <th></th>
+ </tr>
+ %for i, association in enumerate( shared_by_others ):
+ <% workflow = association.stored_workflow %>
+ <tr>
+ <td>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">${workflow.name | h}</a>
+ </td>
+ <td>${workflow.user.email}</td>
+ <td>${len(workflow.latest_workflow.steps)}</td>
+ <td>
+ <div popupmenu="shared-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='display_by_username_and_slug', username=workflow.user.username, slug=workflow.slug)}" target="_top">View</a>
+ <a class="action-button" href="${h.url_for( action='run', id=trans.security.encode_id(workflow.id) )}">Run</a>
+ <a class="action-button" href="${h.url_for( action='clone', id=trans.security.encode_id(workflow.id) )}">Clone</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
- No workflows have been shared with you.
+ No workflows have been shared with you.
-%endif
+ %endif
-<h2>Other options</h2>
+ <h2>Other options</h2>
-<a class="action-button" href="${h.url_for( action='configure_menu' )}">
- <span>Configure your workflow menu</span>
-</a>
\ No newline at end of file
+ <a class="action-button" href="${h.url_for( action='configure_menu' )}">
+ <span>Configure your workflow menu</span>
+ </a>
+ </div>
+ </div>
+</%def>
\ No newline at end of file
diff -r 48e83411aa91 -r 96ec861b4b6e templates/workflow/list_published.mako
--- a/templates/workflow/list_published.mako Fri Mar 12 16:11:26 2010 -0500
+++ b/templates/workflow/list_published.mako Sun Mar 14 11:49:44 2010 -0400
@@ -10,7 +10,7 @@
</%def>
<%def name="title()">
- Galaxy :: Published Workflows
+ Galaxy | Published Workflows
</%def>
<%def name="stylesheets()">
diff -r 48e83411aa91 -r 96ec861b4b6e test/base/twilltestcase.py
--- a/test/base/twilltestcase.py Fri Mar 12 16:11:26 2010 -0500
+++ b/test/base/twilltestcase.py Sun Mar 14 11:49:44 2010 -0400
@@ -791,7 +791,7 @@
self.home()
# Create user, setting username to email.
self.visit_page( "user/create?email=%s&username=%s&password=%s&confirm=%s&create_user_button=Submit" % ( email, email, password, password ) )
- self.check_page_for_string( "Now logged in as %s" %email )
+ self.check_page_for_string( "now logged in as %s" %email )
self.home()
# Make sure a new private role was created for the user
self.visit_page( "user/set_default_permissions" )
@@ -816,7 +816,7 @@
for index, info_value in enumerate(user_info_values):
tc.fv( "1", "field_%i" % index, info_value )
tc.submit( "create_user_button" )
- self.check_page_for_string( "Now logged in as %s" % email )
+ self.check_page_for_string( "now logged in as %s" % email )
def create_user_with_info_as_admin( self, email, password, username, user_info_forms, user_info_form_id, user_info_values ):
'''
This method registers a new user and also provides use info as an admin
@@ -906,16 +906,17 @@
self.create( email=email, password=password )
except:
self.home()
- self.visit_url( "%s/user/login" % self.url )
+ # HACK: don't use panels because late_javascripts() messes up the twill browser and it can't find form fields (and hence user can't be logged in).
+ self.visit_url( "%s/user/login?use_panels=False" % self.url )
tc.fv( '1', 'email', email )
tc.fv( '1', 'password', password )
tc.submit( 'Login' )
- self.check_page_for_string( "Now logged in as %s" %email )
+ self.check_page_for_string( "now logged in as %s" %email )
self.home()
def logout( self ):
self.home()
self.visit_page( "user/logout" )
- self.check_page_for_string( "You are no longer logged in" )
+ self.check_page_for_string( "You have been logged out" )
self.home()
# Functions associated with browsers, cookies, HTML forms and page visits
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/48e83411aa91
changeset: 3528:48e83411aa91
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Fri Mar 12 16:11:26 2010 -0500
description:
New separate functional test scripts for testing admin features, library features, library security and data security. These use a new test_db_util module for all db interaction ( other functional test scripts can be enhanced to use this ). A lot of code cleanup in the functional tests. In twilltestcase, cleaned up library and security related methods to mirror names in recently merged library code.
diffstat:
lib/galaxy/web/controllers/library_common.py | 7 +-
test/base/test_db_util.py | 123 +
test/base/twilltestcase.py | 342 ++-
test/functional/test_admin_features.py | 422 ++++
test/functional/test_data_security.py | 196 ++
test/functional/test_library_features.py | 606 ++++++
test/functional/test_library_security.py | 603 ++++++
test/functional/test_security_and_libraries.py | 2141 ------------------------
8 files changed, 2167 insertions(+), 2273 deletions(-)
diffs (truncated from 4641 to 3000 lines):
diff -r e39c9a2a0b4c -r 48e83411aa91 lib/galaxy/web/controllers/library_common.py
--- a/lib/galaxy/web/controllers/library_common.py Fri Mar 12 14:27:04 2010 -0500
+++ b/lib/galaxy/web/controllers/library_common.py Fri Mar 12 16:11:26 2010 -0500
@@ -155,7 +155,7 @@
library.root_folder.description = new_description
trans.sa_session.add_all( ( library, library.root_folder ) )
trans.sa_session.flush()
- msg = "Library '%s' has been renamed to '%s'" % ( old_name, new_name )
+ msg = "The information has been updated."
return trans.response.send_redirect( web.url_for( controller='library_common',
action='library_info',
cntrller=cntrller,
@@ -313,7 +313,7 @@
folder.description = new_description
trans.sa_session.add( folder )
trans.sa_session.flush()
- msg = "Folder '%s' has been renamed to '%s'" % ( old_name, new_name )
+ msg = "The information has been updated."
messagetype='done'
else:
msg = "You are not authorized to edit this folder"
@@ -698,7 +698,6 @@
trans.app.security_agent.derive_roles_from_access( trans, trans.app.security.decode_id( library_id ), cntrller, library=True, **vars )
if error:
messagetype = 'error'
-
trans.response.send_redirect( web.url_for( controller='library_common',
action='upload_library_dataset',
cntrller=cntrller,
@@ -1171,7 +1170,7 @@
library_dataset.info = new_info
trans.sa_session.add( library_dataset )
trans.sa_session.flush()
- msg = "Dataset '%s' has been renamed to '%s'" % ( old_name, new_name )
+ msg = "The information has been updated."
messagetype = 'done'
else:
msg = "You are not authorized to change the attributes of this dataset"
diff -r e39c9a2a0b4c -r 48e83411aa91 test/base/test_db_util.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/base/test_db_util.py Fri Mar 12 16:11:26 2010 -0500
@@ -0,0 +1,123 @@
+import galaxy.model
+from galaxy.model.orm import *
+from galaxy.model.mapping import context as sa_session
+from base.twilltestcase import *
+import sys
+
+def flush( obj ):
+ sa_session.add( obj )
+ sa_session.flush()
+def get_all_histories_for_user( user ):
+ return sa_session.query( galaxy.model.History ) \
+ .filter( and_( galaxy.model.History.table.c.user_id==user.id,
+ galaxy.model.History.table.c.deleted==False ) ) \
+ .all()
+def get_dataset_permissions_by_dataset( dataset ):
+ return sa_session.query( galaxy.model.DatasetPermissions ) \
+ .filter( galaxy.model.DatasetPermissions.table.c.dataset_id==dataset.id ) \
+ .all()
+def get_dataset_permissions_by_role( role ):
+ return sa_session.query( galaxy.model.DatasetPermissions ) \
+ .filter( galaxy.model.DatasetPermissions.table.c.role_id == role.id ) \
+ .first()
+def get_default_history_permissions_by_history( history ):
+ return sa_session.query( galaxy.model.DefaultHistoryPermissions ) \
+ .filter( galaxy.model.DefaultHistoryPermissions.table.c.history_id==history.id ) \
+ .all()
+def get_default_history_permissions_by_role( role ):
+ return sa_session.query( galaxy.model.DefaultHistoryPermissions ) \
+ .filter( galaxy.model.DefaultHistoryPermissions.table.c.role_id == role.id ) \
+ .all()
+def get_default_user_permissions_by_role( role ):
+ return sa_session.query( galaxy.model.DefaultUserPermissions ) \
+ .filter( galaxy.model.DefaultUserPermissions.table.c.role_id == role.id ) \
+ .all()
+def get_default_user_permissions_by_user( user ):
+ return sa_session.query( galaxy.model.DefaultUserPermissions ) \
+ .filter( galaxy.model.DefaultUserPermissions.table.c.user_id==user.id ) \
+ .all()
+def get_form( name ):
+ fdc_list = sa_session.query( galaxy.model.FormDefinitionCurrent ) \
+ .filter( galaxy.model.FormDefinitionCurrent.table.c.deleted == False ) \
+ .order_by( galaxy.model.FormDefinitionCurrent.table.c.create_time.desc() )
+ for fdc in fdc_list:
+ sa_session.refresh( fdc )
+ sa_session.refresh( fdc.latest_form )
+ if fdc.latest_form.name == name:
+ return fdc.latest_form
+ return None
+def get_folder( parent_id, name, description ):
+ return sa_session.query( galaxy.model.LibraryFolder ) \
+ .filter( and_( galaxy.model.LibraryFolder.table.c.parent_id==parent_id,
+ galaxy.model.LibraryFolder.table.c.name==name,
+ galaxy.model.LibraryFolder.table.c.description==description ) ) \
+ .first()
+def get_group_by_name( name ):
+ return sa_session.query( galaxy.model.Group ).filter( galaxy.model.Group.table.c.name==name ).first()
+def get_group_role_associations_by_group( group ):
+ return sa_session.query( galaxy.model.GroupRoleAssociation ) \
+ .filter( galaxy.model.GroupRoleAssociation.table.c.group_id == group.id ) \
+ .all()
+def get_group_role_associations_by_role( role ):
+ return sa_session.query( galaxy.model.GroupRoleAssociation ) \
+ .filter( galaxy.model.GroupRoleAssociation.table.c.role_id == role.id ) \
+ .all()
+def get_latest_dataset():
+ return sa_session.query( galaxy.model.Dataset ) \
+ .order_by( desc( galaxy.model.Dataset.table.c.create_time ) ) \
+ .first()
+def get_latest_hda():
+ return sa_session.query( galaxy.model.HistoryDatasetAssociation ) \
+ .order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ) \
+ .first()
+def get_latest_history_for_user( user ):
+ return sa_session.query( galaxy.model.History ) \
+ .filter( and_( galaxy.model.History.table.c.deleted==False,
+ galaxy.model.History.table.c.user_id==user.id ) ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
+ .first()
+def get_latest_ldda():
+ return sa_session.query( galaxy.model.LibraryDatasetDatasetAssociation ) \
+ .order_by( desc( galaxy.model.LibraryDatasetDatasetAssociation.table.c.create_time ) ) \
+ .first()
+def get_latest_lddas( limit ):
+ return sa_session.query( galaxy.model.LibraryDatasetDatasetAssociation ) \
+ .order_by( desc( galaxy.model.LibraryDatasetDatasetAssociation.table.c.update_time ) ) \
+ .limit( limit )
+def get_library( name, description, synopsis ):
+ return sa_session.query( galaxy.model.Library ) \
+ .filter( and_( galaxy.model.Library.table.c.name==name,
+ galaxy.model.Library.table.c.description==description,
+ galaxy.model.Library.table.c.synopsis==synopsis,
+ galaxy.model.Library.table.c.deleted==False ) ) \
+ .first()
+def get_private_role( user ):
+ for role in user.all_roles():
+ if role.name == user.email and role.description == 'Private Role for %s' % user.email:
+ return role
+ raise AssertionError( "Private role not found for user '%s'" % user.email )
+def get_role_by_name( name ):
+ return sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first()
+def get_user( email ):
+ return sa_session.query( galaxy.model.User ) \
+ .filter( galaxy.model.User.table.c.email==email ) \
+ .first()
+def get_user_group_associations_by_group( group ):
+ return sa_session.query( galaxy.model.UserGroupAssociation ) \
+ .filter( galaxy.model.UserGroupAssociation.table.c.group_id == group.id ) \
+ .all()
+def get_user_role_associations_by_role( role ):
+ return sa_session.query( galaxy.model.UserRoleAssociation ) \
+ .filter( galaxy.model.UserRoleAssociation.table.c.role_id == role.id ) \
+ .all()
+def refresh( obj ):
+ sa_session.refresh( obj )
+def set_library_permissions( in_list ):
+ permissions_in = []
+ permissions_out = []
+ for k, v in galaxy.model.Library.permitted_actions.items():
+ if k in in_list:
+ permissions_in.append( k )
+ else:
+ permissions_out.append( k )
+ return permissions_in, permissions_out
diff -r e39c9a2a0b4c -r 48e83411aa91 test/base/twilltestcase.py
--- a/test/base/twilltestcase.py Fri Mar 12 14:27:04 2010 -0500
+++ b/test/base/twilltestcase.py Fri Mar 12 16:11:26 2010 -0500
@@ -535,21 +535,55 @@
if check_str:
self.check_page_for_string( check_str )
self.home()
- def edit_hda_attribute_info( self, hda_id, new_name='', new_info='', new_dbkey='', new_startcol='' ):
+ def edit_hda_attribute_info( self, hda_id, new_name='', new_info='', new_dbkey='', new_startcol='',
+ check_str1='', check_str2='', check_str3='', check_str4='',
+ not_displayed1='', not_displayed2='', not_displayed3='' ):
"""Edit history_dataset_association attribute information"""
self.home()
self.visit_url( "%s/root/edit?id=%s" % ( self.url, hda_id ) )
+ submit_required = False
self.check_page_for_string( 'Edit Attributes' )
if new_name:
tc.fv( 'edit_attributes', 'name', new_name )
+ submit_required = True
if new_info:
tc.fv( 'edit_attributes', 'info', new_info )
+ submit_required = True
if new_dbkey:
tc.fv( 'edit_attributes', 'dbkey', new_dbkey )
+ submit_required = True
if new_startcol:
tc.fv( 'edit_attributes', 'startCol', new_startcol )
- tc.submit( 'save' )
- self.check_page_for_string( 'Attributes updated' )
+ submit_required = True
+ if submit_required:
+ tc.submit( 'save' )
+ self.check_page_for_string( 'Attributes updated' )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ if check_str3:
+ self.check_page_for_string( check_str3 )
+ if check_str4:
+ self.check_page_for_string( check_str4 )
+ if not_displayed1:
+ try:
+ self.check_page_for_string( not_displayed1 )
+ raise AssertionError, "String (%s) incorrectly displayed on Edit Attributes page." % not_displayed
+ except:
+ pass
+ if not_displayed2:
+ try:
+ self.check_page_for_string( not_displayed2 )
+ raise AssertionError, "String (%s) incorrectly displayed on Edit Attributes page." % not_displayed
+ except:
+ pass
+ if not_displayed3:
+ try:
+ self.check_page_for_string( not_displayed3 )
+ raise AssertionError, "String (%s) incorrectly displayed on Edit Attributes page." % not_displayed
+ except:
+ pass
self.home()
def auto_detect_metadata( self, hda_id ):
"""Auto-detect history_dataset_association metadata"""
@@ -1164,12 +1198,10 @@
check_str = "Purged 1 users"
self.check_page_for_string( check_str )
self.home()
- def associate_roles_and_groups_with_user( self, user_id, email,
- in_role_ids=[], out_role_ids=[],
- in_group_ids=[], out_group_ids=[],
- check_str='' ):
+ def manage_roles_and_groups_for_user( self, user_id, in_role_ids=[], out_role_ids=[],
+ in_group_ids=[], out_group_ids=[], check_str='' ):
self.home()
- url = "%s/admin/manage_roles_and_groups_for_user?id=%s&user_roles_groups_edit_button=Save" % ( self.url, user_id )
+ url = "%s/admin/manage_roles_and_groups_for_user?id=%s" % ( self.url, user_id )
if in_role_ids:
url += "&in_roles=%s" % ','.join( in_role_ids )
if out_role_ids:
@@ -1178,12 +1210,18 @@
url += "&in_groups=%s" % ','.join( in_group_ids )
if out_group_ids:
url += "&out_groups=%s" % ','.join( out_group_ids )
+ if in_role_ids or out_role_ids or in_group_ids or out_group_ids:
+ url += "&user_roles_groups_edit_button=Save"
self.visit_url( url )
if check_str:
self.check_page_for_string( check_str )
self.home()
# Tests associated with roles
+ def browse_roles( self, check_str1='' ):
+ self.visit_url( '%s/admin/roles' % self.url )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
def create_role( self,
name='Role One',
description="This is Role One",
@@ -1280,6 +1318,10 @@
self.visit_url( "%s/admin/groups" % self.url )
self.check_page_for_string( name )
self.home()
+ def browse_groups( self, check_str1='' ):
+ self.visit_url( '%s/admin/groups' % self.url )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
def rename_group( self, group_id, name='Group One Renamed' ):
"""Rename a group"""
self.home()
@@ -1532,6 +1574,58 @@
self.check_page_for_string( 'Address <b>%s</b> has been added' % address_dict[ 'short_desc' ] )
# Library stuff
+ def add_library_template( self, cntrller, item_type, library_id, form_id, form_name, folder_id=None, ldda_id=None ):
+ """Add a new info template to a library item"""
+ self.home()
+ if item_type == 'library':
+ url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s" % \
+ ( self.url, cntrller, item_type, library_id )
+ elif item_type == 'folder':
+ url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s" % \
+ ( self.url, cntrller, item_type, library_id, folder_id )
+ elif item_type == 'ldda':
+ url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s&ldda_id=%s" % \
+ ( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
+ self.visit_url( url )
+ self.check_page_for_string ( "Select a template for the" )
+ tc.fv( '1', 'form_id', form_id )
+ tc.fv( '1', 'inherit', '1' )
+ tc.submit( 'add_template_button' )
+ self.check_page_for_string = 'A template based on the form "%s" has been added to this' % form_name
+ self.home()
+ def browse_libraries_admin( self, deleted=False, check_str1='', check_str2='', not_displayed1='' ):
+ self.visit_url( '%s/library_admin/browse_libraries?sort=name&f-description=All&f-name=All&f-deleted=%s' % ( self.url, str( deleted ) ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ if not_displayed1:
+ try:
+ self.check_page_for_string( not_displayed1 )
+ raise AssertionError, "String (%s) incorrectly displayed when browing library." % not_displayed1
+ except:
+ pass
+ def browse_libraries_regular_user( self, check_str1='', check_str2='' ):
+ self.visit_url( '%s/library/browse_libraries' % self.url )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ def browse_library( self, cntrller, id, show_deleted=False,
+ check_str1='', check_str2='', check_str3='', not_displayed='', not_displayed2='' ):
+ self.visit_url( '%s/library_common/browse_library?cntrller=%s&id=%s&show_deleted=%s' % ( self.url, cntrller, id, str( show_deleted ) ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ if check_str3:
+ self.check_page_for_string( check_str3 )
+ if not_displayed:
+ try:
+ self.check_page_for_string( not_displayed )
+ raise AssertionError, "String (%s) incorrectly displayed when browing library." % not_displayed
+ except:
+ pass
def create_library( self, name='Library One', description='This is Library One', synopsis='Synopsis for Library One' ):
"""Create a new library"""
self.home()
@@ -1544,6 +1638,28 @@
check_str = "The new library named '%s' has been created" % name
self.check_page_for_string( check_str )
self.home()
+ def library_info( self, cntrller, library_id, library_name, new_name='', new_description='', new_synopsis='',
+ ele_1_field_name='', ele_1_contents='', ele_2_field_name='', ele_2_contents='', check_str1='' ):
+ """Edit information about a library, optionally using an existing template with up to 2 elements"""
+ self.home()
+ self.visit_url( "%s/library_common/library_info?cntrller=%s&id=%s" % ( self.url, cntrller, library_id ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if new_name and new_description and new_synopsis:
+ tc.fv( '1', 'name', new_name )
+ tc.fv( '1', 'description', new_description )
+ tc.fv( '1', 'synopsis', new_synopsis )
+ tc.submit( 'library_info_button' )
+ self.check_page_for_string( "The information has been updated." )
+ # If there is a template, then there are 2 forms on this page and the template is the 2nd form
+ if ele_1_field_name and ele_1_contents and ele_2_field_name and ele_2_contents:
+ tc.fv( '2', ele_1_field_name, ele_1_contents )
+ tc.fv( '2', ele_2_field_name, ele_2_contents )
+ tc.submit( 'edit_info_button' )
+ elif ele_1_field_name and ele_1_contents:
+ tc.fv( '2', ele_1_field_name, ele_1_contents )
+ tc.submit( 'edit_info_button' )
+ self.home()
def library_permissions( self, library_id, library_name, role_ids_str, permissions_in, permissions_out, cntrller='library_admin' ):
# role_ids_str must be a comma-separated string of role ids
url = "library_common/library_permissions?id=%s&cntrller=%slibrary_admin&update_roles_button=Save" % ( library_id, cntrller )
@@ -1558,46 +1674,8 @@
check_str = "Permissions updated for library '%s'" % library_name
self.check_page_for_string( check_str )
self.home()
- def rename_library( self, library_id, old_name, name='Library One Renamed', description='This is Library One Re-described',
- synopsis='This is the new synopsis for Library One ', controller='library_admin' ):
- """Rename a library"""
- self.home()
- self.visit_url( "%s/library_common/library_info?id=%s&cntrller=%s" % ( self.url, library_id, controller ) )
- self.check_page_for_string( old_name )
- # Since twill barfs on the form submisson, we ar forced to simulate it
- url = "%s/library_common/library_info?id=%s&cntrller=%s&library_info_button=Save&description=%s&name=%s&synopsis=%s" % \
- ( self.url, library_id, controller, description.replace( ' ', '+' ), name.replace( ' ', '+' ), synopsis.replace( ' ', '+' ) )
- self.home()
- self.visit_url( url )
- check_str = "Library '%s' has been renamed to '%s'" % ( old_name, name )
- self.check_page_for_string( check_str )
- self.home()
- def add_template( self, cntrller, item_type, library_id, form_id, form_name, folder_id=None, ldda_id=None ):
- """Add a new info template to a library item"""
- self.home()
- if item_type == 'library':
- url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s" % ( self.url, cntrller, item_type, library_id )
- elif item_type == 'folder':
- url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s" % ( self.url, cntrller, item_type, library_id, folder_id )
- elif item_type == 'ldda':
- url = "%s/library_common/add_template?cntrller=%s&item_type=%s&library_id=%s&folder_id=%s&ldda_id=%s" % ( self.url, cntrller, item_type, library_id, folder_id, ldda_id )
- self.visit_url( url )
- self.check_page_for_string ( "Select a template for the" )
- tc.fv( '1', 'form_id', form_id )
- tc.fv( '1', 'inherit', '1' )
- tc.submit( 'add_template_button' )
- self.check_page_for_string = 'A template based on the form "%s" has been added to this' % form_name
- self.home()
- def library_info( self, library_id, library_name, ele_1_field_name, ele_1_contents, ele_2_field_name, ele_2_contents, controller='library_admin' ):
- """Add information to a library using an existing template with 2 elements"""
- self.home()
- self.visit_url( "%s/library_common/library_info?id=%s&cntrller=%s" % ( self.url, library_id, controller ) )
- check_str = 'Other information about library %s' % library_name
- self.check_page_for_string( check_str )
- tc.fv( '2', ele_1_field_name, ele_1_contents )
- tc.fv( '2', ele_2_field_name, ele_2_contents )
- tc.submit( 'create_new_info_button' )
- self.home()
+
+ # Library folder stuff
def add_folder( self, controller, library_id, folder_id, name='Folder One', description='This is Folder One' ):
"""Create a new folder"""
self.home()
@@ -1609,27 +1687,40 @@
check_str = "The new folder named '%s' has been added to the data library." % name
self.check_page_for_string( check_str )
self.home()
- def folder_info( self, controller, folder_id, library_id, name, new_name, description, contents='', field_name='' ):
+ def folder_info( self, cntrller, folder_id, library_id, name='', new_name='', description='',
+ field_name='', contents='', check_str1='', check_str2='', not_displayed='' ):
"""Add information to a library using an existing template with 2 elements"""
self.home()
self.visit_url( "%s/library_common/folder_info?cntrller=%s&id=%s&library_id=%s" % \
- ( self.url, controller, folder_id, library_id) )
+ ( self.url, cntrller, folder_id, library_id ) )
# Twill cannot handle the following call for some reason - it's buggy
# self.check_page_for_string( "Edit folder name and description" )
- tc.fv( '1', "name", new_name )
- tc.fv( '1', "description", description )
- tc.submit( 'rename_folder_button' )
- # Twill cannot handle the following call for some reason - it's buggy
- # check_str = "Folder '%s' has been renamed to '%s'" % ( name, new_name )
- # self.check_page_for_string( check_str )
- if contents and field_name:
+ if name and new_name and description:
+ tc.fv( '1', "name", new_name )
+ tc.fv( '1', "description", description )
+ tc.submit( 'rename_folder_button' )
+ # Twill barfs on this, so keep it commented...
+ #self.check_page_for_string( "The information has been updated." )
+ if field_name and contents:
# We have an information template associated with the folder, so
# there are 2 forms on this page and the template is the 2nd form
tc.fv( '2', field_name, contents )
tc.submit( 'edit_info_button' )
- # Twill cannot handle the following call for some reason - it's buggy
- # self.check_page_for_string( 'The information has been updated.' )
+ # Twill barfs on this, so keep it commented...
+ #self.check_page_for_string( 'The information has been updated.' )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ if not_displayed:
+ try:
+ self.check_page_for_string( not_displayed )
+ raise AssertionError, "String (%s) should not have been displayed on folder info page." % not_displayed
+ except:
+ pass
self.home()
+
+ # Library dataset stuff
def add_library_dataset( self, cntrller, filename, library_id, folder_id, folder_name,
file_type='auto', dbkey='hg18', roles=[], message='', root=False,
template_field_name1='', template_field_contents1='', show_deleted='False',
@@ -1638,7 +1729,7 @@
filename = self.get_filename( filename )
self.home()
self.visit_url( "%s/library_common/upload_library_dataset?cntrller=%s&library_id=%s&folder_id=%s&upload_option=%s&message=%s" % \
- ( self.url, cntrller, library_id, folder_id, upload_option, message ) )
+ ( self.url, cntrller, library_id, folder_id, upload_option, message.replace( ' ', '+' ) ) )
self.check_page_for_string( 'Upload files' )
tc.fv( "1", "library_id", library_id )
tc.fv( "1", "folder_id", folder_id )
@@ -1659,68 +1750,77 @@
check_str = "Added 1 datasets to the folder '%s' (each is selected)." % folder_name
self.library_wait( library_id )
self.home()
- def set_library_dataset_permissions( self, cntrller, library_id, folder_id, ldda_id, ldda_name, role_ids_str, permissions_in, permissions_out ):
+ def ldda_permissions( self, cntrller, library_id, folder_id, id, role_ids_str,
+ permissions_in=[], permissions_out=[], check_str1='' ):
# role_ids_str must be a comma-separated string of role ids
- url = "library_common/ldda_permissions?cntrller=%s&library_id=%s&folder_id=%s&id=%s&update_roles_button=Save" % \
- ( cntrller, library_id, folder_id, ldda_id )
+ url = "%s/library_common/ldda_permissions?cntrller=%s&library_id=%s&folder_id=%s&id=%s" % \
+ ( self.url, cntrller, library_id, folder_id, id )
for po in permissions_out:
key = '%s_out' % po
url ="%s&%s=%s" % ( url, key, role_ids_str )
for pi in permissions_in:
key = '%s_in' % pi
url ="%s&%s=%s" % ( url, key, role_ids_str )
- self.home()
- self.visit_url( "%s/%s" % ( self.url, url ) )
- check_str = "Permissions have been updated on 1 datasets"
+ if permissions_in or permissions_out:
+ url += "&update_roles_button=Save"
+ self.visit_url( url )
+ if check_str1:
+ check_str = check_str1
+ else:
+ check_str = "Permissions have been updated on 1 datasets"
self.check_page_for_string( check_str )
self.home()
- def edit_ldda_template_element_info( self, library_id, folder_id, ldda_id, ldda_name, ele_1_field_name,
- ele_1_contents, ele_2_field_name, ele_2_contents, ele_1_help='', ele_2_help='',
- ele_3_field_name='', ele_3_contents='', ele_3_help='' ):
- """Edit library_dataset_dataset_association template element information"""
- self.home()
- self.visit_url( "%s/library_common/ldda_edit_info?cntrller=library_admin&library_id=%s&folder_id=%s&id=%s" % \
- ( self.url, library_id, folder_id, ldda_id ) )
+ def ldda_edit_info( self, cntrller, library_id, folder_id, ldda_id, ldda_name, new_ldda_name='',
+ ele_1_field_name='', ele_1_contents='', ele_1_help='',
+ ele_2_field_name='', ele_2_contents='', ele_2_help='',
+ ele_3_field_name='', ele_3_contents='', ele_3_help='',
+ check_str1='', check_str2='', check_str3='', not_displayed='' ):
+ """Edit library_dataset_dataset_association information, optionally template element information"""
+ self.visit_url( "%s/library_common/ldda_edit_info?cntrller=%s&library_id=%s&folder_id=%s&id=%s" % \
+ ( self.url, cntrller, library_id, folder_id, ldda_id ) )
check_str = 'Edit attributes of %s' % ldda_name
self.check_page_for_string( check_str )
- ele_1_contents = ele_1_contents.replace( '+', ' ' )
- ele_2_contents = ele_2_contents.replace( '+', ' ' )
- tc.fv( '4', ele_1_field_name, ele_1_contents )
- tc.fv( '4', ele_2_field_name, ele_2_contents.replace( '+', ' ' ) )
+ if new_ldda_name:
+ tc.fv( '1', 'name', new_ldda_name )
+ tc.submit( 'save' )
+ check_str = 'Attributes updated for library dataset %s' % new_ldda_name
+ self.check_page_for_string( check_str )
+ # There are 4 forms on this page and the template is the 4th form
+ if ele_1_field_name and ele_1_contents:
+ ele_1_contents = ele_1_contents.replace( '+', ' ' )
+ tc.fv( '4', ele_1_field_name, ele_1_contents )
+ if ele_2_field_name and ele_2_contents:
+ ele_2_contents = ele_2_contents.replace( '+', ' ' )
+ tc.fv( '4', ele_2_field_name, ele_2_contents.replace( '+', ' ' ) )
if ele_3_field_name and ele_3_contents:
ele_3_contents = ele_3_contents.replace( '+', ' ' )
tc.fv( '4', ele_3_field_name, ele_3_contents )
- tc.submit( 'edit_info_button' )
- self.check_page_for_string( 'This is the latest version of this library dataset' )
- self.check_page_for_string( 'The information has been updated.' )
- self.check_page_for_string( ele_1_contents )
- self.check_page_for_string( ele_2_contents )
- if ele_3_field_name and ele_3_contents:
+ if ele_1_field_name:
+ tc.submit( 'edit_info_button' )
+ self.check_page_for_string( 'This is the latest version of this library dataset' )
+ self.check_page_for_string( 'The information has been updated.' )
+ self.check_page_for_string( ele_1_contents )
+ if ele_2_field_name:
+ self.check_page_for_string( ele_2_contents )
+ if ele_3_field_name:
self.check_page_for_string( ele_3_contents )
if ele_1_help:
check_str = ele_1_help.replace( '+', ' ' )
self.check_page_for_string( check_str )
- self.check_page_for_string( ele_2_contents )
if ele_2_help:
check_str = ele_2_help.replace( '+', ' ' )
self.check_page_for_string( check_str )
if ele_2_help:
check_str = ele_3_help.replace( '+', ' ' )
self.check_page_for_string( check_str )
- self.home()
- def edit_ldda_attribute_info( self, cntrller, library_id, folder_id, ldda_id, ldda_name, new_ldda_name ):
- """Edit library_dataset_dataset_association attribute information"""
- self.home()
- self.visit_url( "%s/library_common/ldda_edit_info?cntrller=%s&library_id=%s&folder_id=%s&id=%s" % \
- ( self.url, cntrller, library_id, folder_id, ldda_id ) )
- check_str = 'Edit attributes of %s' % ldda_name
- self.check_page_for_string( check_str )
- tc.fv( '1', 'name', new_ldda_name )
- tc.submit( 'save' )
- check_str = 'Attributes updated for library dataset %s' % new_ldda_name
- self.check_page_for_string( check_str )
- check_str = 'Edit attributes of %s' % new_ldda_name
- self.check_page_for_string( check_str )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if not_displayed:
+ try:
+ self.check_page_for_string( not_displayed )
+ raise AssertionError, "String (%s) should not have been displayed on ldda Edit Attributes page." % not_displayed
+ except:
+ pass
self.home()
def upload_new_dataset_version( self, cntrller, filename, library_id, folder_id, folder_name, library_dataset_id, ldda_name, file_type='auto',
dbkey='hg18', message='', template_field_name1='', template_field_contents1='' ):
@@ -1755,19 +1855,21 @@
check_str = "Added 1 datasets to the folder '%s' (each is selected)." % folder_name
self.check_page_for_string( check_str )
self.home()
- def add_dir_of_files_from_admin_view( self, library_id, folder_id, file_type='auto', dbkey='hg18', roles_tuple=[],
- message='', check_str_after_submit='', template_field_name1='', template_field_contents1='' ):
+ def upload_directory_of_files( self, cntrller, library_id, folder_id, server_dir, file_type='auto', dbkey='hg18', roles_tuple=[],
+ message='', check_str1='', check_str_after_submit='', template_field_name1='', template_field_contents1='' ):
"""Add a directory of datasets to a folder"""
# roles is a list of tuples: [ ( role_id, role_description ) ]
- self.home()
- self.visit_url( "%s/library_common/upload_library_dataset?cntrller=library_admin&upload_option=upload_directory&library_id=%s&folder_id=%s" % \
- ( self.url, library_id, folder_id ) )
+ url = "%s/library_common/upload_library_dataset?cntrller=%s&library_id=%s&folder_id=%s&upload_option=upload_directory" % \
+ ( self.url, cntrller, library_id, folder_id )
+ self.visit_url( url )
self.check_page_for_string( 'Upload a directory of files' )
+ if check_str1:
+ self.check_page_for_strin( check_str1 )
tc.fv( "1", "folder_id", folder_id )
tc.fv( "1", "file_type", file_type )
tc.fv( "1", "dbkey", dbkey )
- tc.fv( "1", "message", message.replace( '+', ' ' ) )
- tc.fv( "1", "server_dir", "library" )
+ tc.fv( "1", "message", message )
+ tc.fv( "1", "server_dir", server_dir )
for role_tuple in roles_tuple:
tc.fv( "1", "roles", role_tuple[1] ) # role_tuple[1] is the role name
# Add template field contents, if any...
@@ -1778,29 +1880,13 @@
self.check_page_for_string( check_str_after_submit )
self.library_wait( library_id )
self.home()
- def add_dir_of_files_from_libraries_view( self, library_id, folder_id, selected_dir, file_type='auto', dbkey='hg18', roles_tuple=[],
- message='', check_str_after_submit='', template_field_name1='', template_field_contents1='' ):
- """Add a directory of datasets to a folder"""
- # roles is a list of tuples: [ ( role_id, role_description ) ]
- self.home()
- self.visit_url( "%s/library_common/upload_library_dataset?cntrller=library&upload_option=upload_directory&library_id=%s&folder_id=%s" % \
- ( self.url, library_id, folder_id ) )
- self.check_page_for_string( 'Upload a directory of files' )
- tc.fv( "1", "folder_id", folder_id )
- tc.fv( "1", "file_type", file_type )
- tc.fv( "1", "dbkey", dbkey )
- tc.fv( "1", "message", message.replace( '+', ' ' ) )
- tc.fv( "1", "server_dir", selected_dir )
- for role_tuple in roles_tuple:
- tc.fv( "1", "roles", role_tuple[1] ) # role_tuple[1] is the role name
- # Add template field contents, if any...
- if template_field_name1:
- tc.fv( "1", template_field_name1, template_field_contents1 )
- tc.submit( "runtool_btn" )
- if check_str_after_submit:
- self.check_page_for_string( check_str_after_submit )
- self.library_wait( library_id, cntrller='library' )
- self.home()
+ def act_on_multiple_datasets( self, cntrller, library_id, do_action, ldda_ids='', check_str1='' ):
+ # Can't use the ~/library_admin/libraries form as twill barfs on it so we'll simulate the form submission
+ # by going directly to the form action
+ self.visit_url( '%s/library_common/act_on_multiple_datasets?cntrller=%s&library_id=%s&ldda_ids=%s&do_action=%s' \
+ % ( self.url, cntrller, library_id, ldda_ids, do_action ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
def download_archive_of_library_files( self, cntrller, library_id, ldda_ids, format ):
self.home()
# Here it would be ideal to have twill set form values and submit the form, but
diff -r e39c9a2a0b4c -r 48e83411aa91 test/functional/test_admin_features.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/functional/test_admin_features.py Fri Mar 12 16:11:26 2010 -0500
@@ -0,0 +1,422 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestDataSecurity( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email "test2(a)bx.psu.edu" from the database'
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
+ def test_005_create_new_user_account_as_admin( self ):
+ """Testing creating a new user account as admin"""
+ # Logged in as admin_user
+ email = 'test3(a)bx.psu.edu'
+ password = 'testuser'
+ previously_created = self.create_new_account_as_admin( email=email, password=password )
+ # Get the user object for later tests
+ global regular_user3
+ regular_user3 = get_user( email )
+ assert regular_user3 is not None, 'Problem retrieving user with email "%s" from the database' % email
+ global regular_user3_private_role
+ regular_user3_private_role = get_private_role( regular_user3 )
+ # Make sure DefaultUserPermissions were created
+ if not regular_user3.default_permissions:
+ raise AssertionError( 'No DefaultUserPermissions were created for user %s when the admin created the account' % email )
+ # Make sure a private role was created for the user
+ if not regular_user3.roles:
+ raise AssertionError( 'No UserRoleAssociations were created for user %s when the admin created the account' % email )
+ if not previously_created and len( regular_user3.roles ) != 1:
+ raise AssertionError( '%d UserRoleAssociations were created for user %s when the admin created the account ( should have been 1 )' \
+ % ( len( regular_user3.roles ), regular_user3.email ) )
+ for ura in regular_user3.roles:
+ role = sa_session.query( galaxy.model.Role ).get( ura.role_id )
+ if not previously_created and role.type != 'private':
+ raise AssertionError( 'Role created for user %s when the admin created the account is not private, type is' \
+ % str( role.type ) )
+ if not previously_created:
+ # Make sure a history was not created ( previous test runs may have left deleted histories )
+ histories = get_all_histories_for_user( regular_user3 )
+ if histories:
+ raise AssertionError( 'Histories were incorrectly created for user %s when the admin created the account' % email )
+ # Make sure the user was not associated with any groups
+ if regular_user3.groups:
+ raise AssertionError( 'Groups were incorrectly associated with user %s when the admin created the account' % email )
+ def test_010_reset_password_as_admin( self ):
+ """Testing reseting a user password as admin"""
+ self.reset_password_as_admin( user_id=self.security.encode_id( regular_user3.id ), password='testreset' )
+ def test_015_login_after_password_reset( self ):
+ """Testing logging in after an admin reset a password - tests DefaultHistoryPermissions for accounts created by an admin"""
+ # logged in as admin_user
+ self.logout()
+ self.login( email=regular_user3.email, password='testreset' )
+ # Make sure a History and HistoryDefaultPermissions exist for the user
+ latest_history = get_latest_history_for_user( regular_user3 )
+ if not latest_history.user_id == regular_user3.id:
+ raise AssertionError( 'A history was not created for user %s when he logged in' % email )
+ if not latest_history.default_permissions:
+ raise AssertionError( 'No DefaultHistoryPermissions were created for history id %d when it was created' % latest_history.id )
+ dhps = get_default_history_permissions_by_history( latest_history )
+ if len( dhps ) > 1:
+ raise AssertionError( 'More than 1 DefaultHistoryPermissions were created for history id %d when it was created' % latest_history.id )
+ dhp = dhps[0]
+ if not dhp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
+ raise AssertionError( 'The DefaultHistoryPermission.action for history id %d is "%s", but it should be "manage permissions"' \
+ % ( latest_history.id, dhp.action ) )
+ # Upload a file to create a HistoryDatasetAssociation
+ self.upload_file( '1.bed' )
+ latest_dataset = get_latest_dataset()
+ for dp in latest_dataset.actions:
+ # Should only have 1 DatasetPermissions
+ if dp.action != galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
+ raise AssertionError( 'The DatasetPermissions for dataset id %d is %s ( should have been %s )' \
+ % ( latest_dataset.id,
+ latest_dataset.actions.action,
+ galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
+ self.logout()
+ # Reset the password to the default for later tests
+ self.login( email='test(a)bx.psu.edu' )
+ self.reset_password_as_admin( user_id=self.security.encode_id( regular_user3.id ), password='testuser' )
+ def test_020_mark_user_deleted( self ):
+ """Testing marking a user account as deleted"""
+ # Logged in as admin_user
+ self.mark_user_deleted( user_id=self.security.encode_id( regular_user3.id ), email=regular_user3.email )
+ if not regular_user3.active_histories:
+ raise AssertionError( 'HistoryDatasetAssociations for regular_user3 were incorrectly deleted when the user was marked deleted' )
+ def test_025_undelete_user( self ):
+ """Testing undeleting a user account"""
+ # Logged in as admin_user
+ self.undelete_user( user_id=self.security.encode_id( regular_user3.id ), email=regular_user3.email )
+ def test_030_create_role( self ):
+ """Testing creating new role with 3 members ( and a new group named the same ), then renaming the role"""
+ # Logged in as admin_user
+ name = 'Role One'
+ description = "This is Role Ones description"
+ user_ids=[ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ]
+ self.create_role( name=name,
+ description=description,
+ in_user_ids=user_ids,
+ in_group_ids=[],
+ create_group_for_role='yes',
+ private_role=admin_user.email )
+ # Get the role object for later tests
+ global role_one
+ role_one = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first()
+ assert role_one is not None, 'Problem retrieving role named "Role One" from the database'
+ # Make sure UserRoleAssociations are correct
+ if len( role_one.users ) != len( user_ids ):
+ raise AssertionError( '%d UserRoleAssociations were created for role id %d when it was created ( should have been %d )' \
+ % ( len( role_one.users ), role_one.id, len( user_ids ) ) )
+ # Each of the following users should now have 2 role associations, their private role and role_one
+ for user in [ admin_user, regular_user1, regular_user3 ]:
+ refresh( user )
+ if len( user.roles ) != 2:
+ raise AssertionError( '%d UserRoleAssociations are associated with user %s ( should be 2 )' \
+ % ( len( user.roles ), user.email ) )
+ # Make sure the group was created
+ self.visit_url( '%s/admin/groups' % self.url )
+ self.check_page_for_string( name )
+ global group_zero
+ group_zero = get_group_by_name( name )
+ # Rename the role
+ rename = "Role One's been Renamed"
+ new_description="This is Role One's Re-described"
+ self.rename_role( self.security.encode_id( role_one.id ), name=rename, description=new_description )
+ self.visit_url( '%s/admin/roles' % self.url )
+ self.check_page_for_string( rename )
+ self.check_page_for_string( new_description )
+ # Reset the role back to the original name and description
+ self.rename_role( self.security.encode_id( role_one.id ), name=name, description=description )
+ def test_035_create_group( self ):
+ """Testing creating new group with 3 members and 1 associated role, then renaming it"""
+ # Logged in as admin_user
+ name = "Group One's Name"
+ user_ids=[ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ]
+ role_ids=[ str( role_one.id ) ]
+ self.create_group( name=name, in_user_ids=user_ids, in_role_ids=role_ids )
+ # Get the group object for later tests
+ global group_one
+ group_one = get_group_by_name( name )
+ assert group_one is not None, 'Problem retrieving group named "Group One" from the database'
+ # Make sure UserGroupAssociations are correct
+ if len( group_one.users ) != len( user_ids ):
+ raise AssertionError( '%d UserGroupAssociations were created for group id %d when it was created ( should have been %d )' \
+ % ( len( group_one.users ), group_one.id, len( user_ids ) ) )
+ # Each user should now have 1 group association, group_one
+ for user in [ admin_user, regular_user1, regular_user3 ]:
+ refresh( user )
+ if len( user.groups ) != 1:
+ raise AssertionError( '%d UserGroupAssociations are associated with user %s ( should be 1 )' % ( len( user.groups ), user.email ) )
+ # Make sure GroupRoleAssociations are correct
+ if len( group_one.roles ) != len( role_ids ):
+ raise AssertionError( '%d GroupRoleAssociations were created for group id %d when it was created ( should have been %d )' \
+ % ( len( group_one.roles ), group_one.id, len( role_ids ) ) )
+ # Rename the group
+ rename = "Group One's been Renamed"
+ self.rename_group( self.security.encode_id( group_one.id ), name=rename, )
+ self.home()
+ self.visit_url( '%s/admin/groups' % self.url )
+ self.check_page_for_string( rename )
+ # Reset the group back to the original name
+ self.rename_group( self.security.encode_id( group_one.id ), name=name )
+ def test_040_add_members_and_role_to_group( self ):
+ """Testing editing user membership and role associations of an existing group"""
+ # Logged in as admin_user
+ name = 'Group Two'
+ self.create_group( name=name, in_user_ids=[], in_role_ids=[] )
+ # Get the group object for later tests
+ global group_two
+ group_two = get_group_by_name( name )
+ assert group_two is not None, 'Problem retrieving group named "Group Two" from the database'
+ # group_two should have no associations
+ if group_two.users:
+ raise AssertionError( '%d UserGroupAssociations were created for group id %d when it was created ( should have been 0 )' \
+ % ( len( group_two.users ), group_two.id ) )
+ if group_two.roles:
+ raise AssertionError( '%d GroupRoleAssociations were created for group id %d when it was created ( should have been 0 )' \
+ % ( len( group_two.roles ), group_two.id ) )
+ user_ids = [ str( regular_user1.id ) ]
+ role_ids = [ str( role_one.id ) ]
+ self.associate_users_and_roles_with_group( self.security.encode_id( group_two.id ),
+ group_two.name,
+ user_ids=user_ids,
+ role_ids=role_ids )
+ def test_045_create_role_with_user_and_group_associations( self ):
+ """Testing creating a role with user and group associations"""
+ # Logged in as admin_user
+ # NOTE: To get this to work with twill, all select lists on the ~/admin/role page must contain at least
+ # 1 option value or twill throws an exception, which is: ParseError: OPTION outside of SELECT
+ # Due to this bug in twill, we create the role, we bypass the page and visit the URL in the
+ # associate_users_and_groups_with_role() method.
+ name = 'Role Two'
+ description = 'This is Role Two'
+ user_ids=[ str( admin_user.id ) ]
+ group_ids=[ str( group_two.id ) ]
+ private_role=admin_user.email
+ # Create the role
+ self.create_role( name=name,
+ description=description,
+ in_user_ids=user_ids,
+ in_group_ids=group_ids,
+ private_role=private_role )
+ # Get the role object for later tests
+ global role_two
+ role_two = get_role_by_name( name )
+ assert role_two is not None, 'Problem retrieving role named "Role Two" from the database'
+ # Make sure UserRoleAssociations are correct
+ if len( role_two.users ) != len( user_ids ):
+ raise AssertionError( '%d UserRoleAssociations were created for role id %d when it was created with %d members' \
+ % ( len( role_two.users ), role_two.id, len( user_ids ) ) )
+ # admin_user should now have 3 role associations, private role, role_one, role_two
+ refresh( admin_user )
+ if len( admin_user.roles ) != 3:
+ raise AssertionError( '%d UserRoleAssociations are associated with user %s ( should be 3 )' % ( len( admin_user.roles ), admin_user.email ) )
+ # Make sure GroupRoleAssociations are correct
+ refresh( role_two )
+ if len( role_two.groups ) != len( group_ids ):
+ raise AssertionError( '%d GroupRoleAssociations were created for role id %d when it was created ( should have been %d )' \
+ % ( len( role_two.groups ), role_two.id, len( group_ids ) ) )
+ # group_two should now be associated with 2 roles: role_one, role_two
+ refresh( group_two )
+ if len( group_two.roles ) != 2:
+ raise AssertionError( '%d GroupRoleAssociations are associated with group id %d ( should be 2 )' % ( len( group_two.roles ), group_two.id ) )
+ def test_050_change_user_role_associations( self ):
+ """Testing changing roles associated with a user"""
+ # Logged in as admin_user
+ # Create a new role with no associations
+ name = 'Role Three'
+ description = 'This is Role Three'
+ user_ids=[]
+ group_ids=[]
+ private_role=admin_user.email
+ self.create_role( name=name,
+ description=description,
+ in_user_ids=user_ids,
+ in_group_ids=group_ids,
+ private_role=private_role )
+ # Get the role object for later tests
+ global role_three
+ role_three = get_role_by_name( name )
+ assert role_three is not None, 'Problem retrieving role named "Role Three" from the database'
+ # Associate the role with a user
+ refresh( admin_user )
+ role_ids = []
+ for ura in admin_user.non_private_roles:
+ role_ids.append( str( ura.role_id ) )
+ role_ids.append( str( role_three.id ) )
+ group_ids = []
+ for uga in admin_user.groups:
+ group_ids.append( str( uga.group_id ) )
+ check_str = "User '%s' has been updated with %d associated roles and %d associated groups" % \
+ ( admin_user.email, len( role_ids ), len( group_ids ) )
+ self.manage_roles_and_groups_for_user( self.security.encode_id( admin_user.id ),
+ in_role_ids=role_ids,
+ in_group_ids=group_ids,
+ check_str=check_str )
+ refresh( admin_user )
+ # admin_user should now be associated with 4 roles: private, role_one, role_two, role_three
+ if len( admin_user.roles ) != 4:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 4 )' % \
+ ( len( admin_user.roles ), admin_user.email ) )
+ def test_055_mark_group_deleted( self ):
+ """Testing marking a group as deleted"""
+ # Logged in as admin_user
+ self.browse_groups( check_str1=group_two.name )
+ self.mark_group_deleted( self.security.encode_id( group_two.id ), group_two.name )
+ refresh( group_two )
+ if not group_two.deleted:
+ raise AssertionError( '%s was not correctly marked as deleted.' % group_two.name )
+ # Deleting a group should not delete any associations
+ if not group_two.members:
+ raise AssertionError( '%s incorrectly lost all members when it was marked as deleted.' % group_two.name )
+ if not group_two.roles:
+ raise AssertionError( '%s incorrectly lost all role associations when it was marked as deleted.' % group_two.name )
+ def test_060_undelete_group( self ):
+ """Testing undeleting a deleted group"""
+ # Logged in as admin_user
+ self.undelete_group( self.security.encode_id( group_two.id ), group_two.name )
+ refresh( group_two )
+ if group_two.deleted:
+ raise AssertionError( '%s was not correctly marked as not deleted.' % group_two.name )
+ def test_065_mark_role_deleted( self ):
+ """Testing marking a role as deleted"""
+ # Logged in as admin_user
+ self.home()
+ self.browse_roles( check_str1=role_two.name )
+ self.mark_role_deleted( self.security.encode_id( role_two.id ), role_two.name )
+ refresh( role_two )
+ if not role_two.deleted:
+ raise AssertionError( '%s was not correctly marked as deleted.' % role_two.name )
+ # Deleting a role should not delete any associations
+ if not role_two.users:
+ raise AssertionError( '%s incorrectly lost all user associations when it was marked as deleted.' % role_two.name )
+ if not role_two.groups:
+ raise AssertionError( '%s incorrectly lost all group associations when it was marked as deleted.' % role_two.name )
+ def test_070_undelete_role( self ):
+ """Testing undeleting a deleted role"""
+ # Logged in as admin_user
+ self.undelete_role( self.security.encode_id( role_two.id ), role_two.name )
+ def test_075_purge_user( self ):
+ """Testing purging a user account"""
+ # Logged in as admin_user
+ self.mark_user_deleted( user_id=self.security.encode_id( regular_user3.id ), email=regular_user3.email )
+ refresh( regular_user3 )
+ self.purge_user( self.security.encode_id( regular_user3.id ), regular_user3.email )
+ refresh( regular_user3 )
+ if not regular_user3.purged:
+ raise AssertionError( 'User %s was not marked as purged.' % regular_user3.email )
+ # Make sure DefaultUserPermissions deleted EXCEPT FOR THE PRIVATE ROLE
+ if len( regular_user3.default_permissions ) != 1:
+ raise AssertionError( 'DefaultUserPermissions for user %s were not deleted.' % regular_user3.email )
+ for dup in regular_user3.default_permissions:
+ role = sa_session.query( galaxy.model.Role ).get( dup.role_id )
+ if role.type != 'private':
+ raise AssertionError( 'DefaultUserPermissions for user %s are not related with the private role.' % regular_user3.email )
+ # Make sure History deleted
+ for history in regular_user3.histories:
+ refresh( history )
+ if not history.deleted:
+ raise AssertionError( 'User %s has active history id %d after their account was marked as purged.' % ( regular_user3.email, hda.id ) )
+ # NOTE: Not all hdas / datasets will be deleted at the time a history is deleted - the cleanup_datasets.py script
+ # is responsible for this.
+ # Make sure UserGroupAssociations deleted
+ if regular_user3.groups:
+ raise AssertionError( 'User %s has active group id %d after their account was marked as purged.' % ( regular_user3.email, uga.id ) )
+ # Make sure UserRoleAssociations deleted EXCEPT FOR THE PRIVATE ROLE
+ if len( regular_user3.roles ) != 1:
+ raise AssertionError( 'UserRoleAssociations for user %s were not deleted.' % regular_user3.email )
+ for ura in regular_user3.roles:
+ role = sa_session.query( galaxy.model.Role ).get( ura.role_id )
+ if role.type != 'private':
+ raise AssertionError( 'UserRoleAssociations for user %s are not related with the private role.' % regular_user3.email )
+ def test_080_manually_unpurge_user( self ):
+ """Testing manually un-purging a user account"""
+ # Logged in as admin_user
+ # Reset the user for later test runs. The user's private Role and DefaultUserPermissions for that role
+ # should have been preserved, so all we need to do is reset purged and deleted.
+ # TODO: If we decide to implement the GUI feature for un-purging a user, replace this with a method call
+ regular_user3.purged = False
+ regular_user3.deleted = False
+ flush( regular_user3 )
+ def test_085_purge_group( self ):
+ """Testing purging a group"""
+ # Logged in as admin_user
+ self.mark_group_deleted( self.security.encode_id( group_two.id ), group_two.name )
+ self.purge_group( self.security.encode_id( group_two.id ), group_two.name )
+ # Make sure there are no UserGroupAssociations
+ if get_user_group_associations_by_group( group_two ):
+ raise AssertionError( "Purging the group did not delete the UserGroupAssociations for group_id '%s'" % group_two.id )
+ # Make sure there are no GroupRoleAssociations
+ if get_group_role_associations_by_group( group_two ):
+ raise AssertionError( "Purging the group did not delete the GroupRoleAssociations for group_id '%s'" % group_two.id )
+ # Undelete the group for later test runs
+ self.undelete_group( self.security.encode_id( group_two.id ), group_two.name )
+ def test_090_purge_role( self ):
+ """Testing purging a role"""
+ # Logged in as admin_user
+ self.mark_role_deleted( self.security.encode_id( role_two.id ), role_two.name )
+ self.purge_role( self.security.encode_id( role_two.id ), role_two.name )
+ # Make sure there are no UserRoleAssociations
+ if get_user_role_associations_by_role( role_two ):
+ raise AssertionError( "Purging the role did not delete the UserRoleAssociations for role_id '%s'" % role_two.id )
+ # Make sure there are no DefaultUserPermissions associated with the Role
+ if get_default_user_permissions_by_role( role_two ):
+ raise AssertionError( "Purging the role did not delete the DefaultUserPermissions for role_id '%s'" % role_two.id )
+ # Make sure there are no DefaultHistoryPermissions associated with the Role
+ if get_default_history_permissions_by_role( role_two ):
+ raise AssertionError( "Purging the role did not delete the DefaultHistoryPermissions for role_id '%s'" % role_two.id )
+ # Make sure there are no GroupRoleAssociations
+ if get_group_role_associations_by_role( role_two ):
+ raise AssertionError( "Purging the role did not delete the GroupRoleAssociations for role_id '%s'" % role_two.id )
+ # Make sure there are no DatasetPermissionss
+ if get_dataset_permissions_by_role( role_two ):
+ raise AssertionError( "Purging the role did not delete the DatasetPermissionss for role_id '%s'" % role_two.id )
+ def test_095_manually_unpurge_role( self ):
+ """Testing manually un-purging a role"""
+ # Logged in as admin_user
+ # Manually unpurge, then undelete the role for later test runs
+ # TODO: If we decide to implement the GUI feature for un-purging a role, replace this with a method call
+ role_two.purged = False
+ flush( role_two )
+ self.undelete_role( self.security.encode_id( role_two.id ), role_two.name )
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
+ # Logged in as admin_user
+ ##################
+ # Eliminate all non-private roles
+ ##################
+ for role in [ role_one, role_two, role_three ]:
+ self.mark_role_deleted( self.security.encode_id( role.id ), role.name )
+ self.purge_role( self.security.encode_id( role.id ), role.name )
+ # Manually delete the role from the database
+ refresh( role )
+ sa_session.delete( role )
+ sa_session.flush()
+ ##################
+ # Eliminate all groups
+ ##################
+ for group in [ group_zero, group_one, group_two ]:
+ self.mark_group_deleted( self.security.encode_id( group.id ), group.name )
+ self.purge_group( self.security.encode_id( group.id ), group.name )
+ # Manually delete the group from the database
+ refresh( group )
+ sa_session.delete( group )
+ sa_session.flush()
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 1 )' % ( len( user.roles ), user.email ) )
diff -r e39c9a2a0b4c -r 48e83411aa91 test/functional/test_data_security.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/functional/test_data_security.py Fri Mar 12 16:11:26 2010 -0500
@@ -0,0 +1,196 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestDataSecurity( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ global regular_user1_private_role
+ regular_user1_private_role = get_private_role( regular_user1 )
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email "test2(a)bx.psu.edu" from the database'
+ global regular_user2_private_role
+ regular_user2_private_role = get_private_role( regular_user2 )
+ self.logout()
+ self.login( email='test3(a)bx.psu.edu' )
+ global regular_user3
+ regular_user3 = get_user( 'test3(a)bx.psu.edu' )
+ assert regular_user3 is not None, 'Problem retrieving user with email "test3(a)bx.psu.edu" from the database'
+ global regular_user3_private_role
+ regular_user3_private_role = get_private_role( regular_user3 )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
+ global admin_user_private_role
+ admin_user_private_role = get_private_role( admin_user )
+ def test_005_default_permissions( self ):
+ """Testing initial settings for DefaultUserPermissions and DefaultHistoryPermissions"""
+ # Logged in as admin_user
+ # Make sure DefaultUserPermissions are correct
+ dups = get_default_user_permissions_by_user( admin_user )
+ if len( dups ) > 1:
+ raise AssertionError( '%d DefaultUserPermissions associated with user %s ( should be 1 )' \
+ % ( len( admin_user.default_permissions ), admin_user.email ) )
+ dup = dups[0]
+ if not dup.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
+ raise AssertionError( 'The DefaultUserPermission.action for user "%s" is "%s", but it should be "%s"' \
+ % ( admin_user.email, dup.action, galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
+ # Make sure DefaultHistoryPermissions are correct
+ latest_history = get_latest_history_for_user( admin_user )
+ dhps = get_default_history_permissions_by_history( latest_history )
+ if len( dhps ) > 1:
+ raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d when it was created ( should have been 1 )' \
+ % ( len( latest_history.default_permissions ), latest_history.id ) )
+ dhp = dhps[0]
+ if not dhp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
+ raise AssertionError( 'The DefaultHistoryPermission.action for history id %d is "%s", but it should be "%s"' \
+ % ( latest_history.id, dhp.action, galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
+ self.manage_roles_and_groups_for_user( self.security.encode_id( admin_user.id ),
+ check_str=admin_user.email )
+ # Try deleting the admin_user's private role
+ check_str = "You cannot eliminate a user's private role association."
+ self.manage_roles_and_groups_for_user( self.security.encode_id( admin_user.id ),
+ out_role_ids=str( admin_user_private_role.id ),
+ check_str=check_str )
+ def test_010_private_role_creation_and_default_history_permissions( self ):
+ """Testing private role creation and changing DefaultHistoryPermissions for new histories"""
+ # Logged in as admin_user
+ self.logout()
+ # Some of the history related tests here are similar to some tests in the
+ # test_history_functions.py script, so we could potentially eliminate 1 or 2 of them.
+ self.login( email='test1(a)bx.psu.edu' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ # Add a dataset to the history
+ self.upload_file( '1.bed' )
+ latest_dataset = get_latest_dataset()
+ # Make sure DatasetPermissions are correct - default is 'manage permissions'
+ dps = get_dataset_permissions_by_dataset( latest_dataset )
+ if len( dps ) > 1:
+ raise AssertionError( '%d DatasetPermissions were created for dataset id %d when it was created ( should have been 1 )' \
+ % ( len( dps ), latest_dataset.id ) )
+ dp = dps[0]
+ if not dp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
+ raise AssertionError( 'The DatasetPermissions.action for dataset id %d is "%s", but it should be "manage permissions"' \
+ % ( latest_dataset.id, dp.action ) )
+ # Change DefaultHistoryPermissions for regular_user1
+ permissions_in = []
+ actions_in = []
+ for key, value in galaxy.model.Dataset.permitted_actions.items():
+ # Setting the 'access' permission with the private role makes this dataset private
+ permissions_in.append( key )
+ actions_in.append( value.action )
+ # Sort actions for later comparison
+ actions_in.sort()
+ self.user_set_default_permissions( permissions_in=permissions_in, role_id=str( regular_user1_private_role.id ) )
+ # Make sure the default permissions are changed for new histories
+ self.new_history()
+ # logged in as regular_user1
+ latest_history = get_latest_history_for_user( regular_user1 )
+ if len( latest_history.default_permissions ) != len( actions_in ):
+ raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d, should have been %d' % \
+ ( len( latest_history.default_permissions ), latest_history.id, len( actions_in ) ) )
+ dhps = []
+ for dhp in latest_history.default_permissions:
+ dhps.append( dhp.action )
+ # Sort permissions for later comparison
+ dhps.sort()
+ for key, value in galaxy.model.Dataset.permitted_actions.items():
+ if value.action not in dhps:
+ raise AssertionError( '%s not in history id %d default_permissions after they were changed' % ( value.action, latest_history.id ) )
+ # Add a dataset to the history
+ self.upload_file( '1.bed' )
+ latest_dataset = get_latest_dataset()
+ # Make sure DatasetPermissions are correct
+ if len( latest_dataset.actions ) != len( latest_history.default_permissions ):
+ raise AssertionError( '%d DatasetPermissions were created for dataset id %d when it was created ( should have been %d )' % \
+ ( len( latest_dataset.actions ), latest_dataset.id, len( latest_history.default_permissions ) ) )
+ dps = []
+ for dp in latest_dataset.actions:
+ dps.append( dp.action )
+ # Sort actions for later comparison
+ dps.sort()
+ # Compare DatasetPermissions with permissions_in - should be the same
+ if dps != actions_in:
+ raise AssertionError( 'DatasetPermissions "%s" for dataset id %d differ from changed default permissions "%s"' \
+ % ( str( dps ), latest_dataset.id, str( actions_in ) ) )
+ # Compare DefaultHistoryPermissions and DatasetPermissions - should be the same
+ if dps != dhps:
+ raise AssertionError( 'DatasetPermissions "%s" for dataset id %d differ from DefaultHistoryPermissions "%s" for history id %d' \
+ % ( str( dps ), latest_dataset.id, str( dhps ), latest_history.id ) )
+ def test_015_change_default_permissions_for_current_history( self ):
+ """Testing changing DefaultHistoryPermissions for the current history"""
+ # logged in a regular_user1
+ self.logout()
+ self.login( email=regular_user2.email )
+ latest_history = get_latest_history_for_user( regular_user2 )
+ self.upload_file( '1.bed' )
+ latest_dataset = get_latest_dataset()
+ permissions_in = [ 'DATASET_MANAGE_PERMISSIONS' ]
+ # Make sure these are in sorted order for later comparison
+ actions_in = [ 'manage permissions' ]
+ permissions_out = [ 'DATASET_ACCESS' ]
+ actions_out = [ 'access' ]
+ # Change DefaultHistoryPermissions for the current history
+ self.history_set_default_permissions( permissions_out=permissions_out, permissions_in=permissions_in, role_id=str( regular_user2_private_role.id ) )
+ if len( latest_history.default_permissions ) != len( actions_in ):
+ raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d, should have been %d' \
+ % ( len( latest_history.default_permissions ), latest_history.id, len( permissions_in ) ) )
+ # Make sure DefaultHistoryPermissions were correctly changed for the current history
+ dhps = []
+ for dhp in latest_history.default_permissions:
+ dhps.append( dhp.action )
+ # Sort permissions for later comparison
+ dhps.sort()
+ # Compare DefaultHistoryPermissions and actions_in - should be the same
+ if dhps != actions_in:
+ raise AssertionError( 'DefaultHistoryPermissions "%s" for history id %d differ from actions "%s" passed for changing' \
+ % ( str( dhps ), latest_history.id, str( actions_in ) ) )
+ # Make sure DatasetPermissionss are correct
+ if len( latest_dataset.actions ) != len( latest_history.default_permissions ):
+ raise AssertionError( '%d DatasetPermissionss were created for dataset id %d when it was created ( should have been %d )' \
+ % ( len( latest_dataset.actions ), latest_dataset.id, len( latest_history.default_permissions ) ) )
+ dps = []
+ for dp in latest_dataset.actions:
+ dps.append( dp.action )
+ # Sort actions for comparison
+ dps.sort()
+ # Compare DatasetPermissionss and DefaultHistoryPermissions - should be the same
+ if dps != dhps:
+ raise AssertionError( 'DatasetPermissionss "%s" for dataset id %d differ from DefaultHistoryPermissions "%s"' \
+ % ( str( dps ), latest_dataset.id, str( dhps ) ) )
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
+ # Logged in as regular_user2
+ self.logout()
+ self.login( email=admin_user.email )
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 1 )' % ( len( user.roles ), user.email ) )
+ #####################
+ # Reset DefaultHistoryPermissions for regular_user1
+ #####################
+ self.logout()
+ self.login( email=regular_user1.email )
+ # Change DefaultHistoryPermissions for regular_user1 back to the default
+ permissions_in = [ 'DATASET_MANAGE_PERMISSIONS' ]
+ permissions_out = [ 'DATASET_ACCESS' ]
+ self.user_set_default_permissions( permissions_in=permissions_in,
+ permissions_out=permissions_out,
+ role_id=str( regular_user1_private_role.id ) )
+ self.logout()
+ self.login( email=admin_user.email )
diff -r e39c9a2a0b4c -r 48e83411aa91 test/functional/test_library_features.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/functional/test_library_features.py Fri Mar 12 16:11:26 2010 -0500
@@ -0,0 +1,606 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestLibraryFeatures( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email "test2(a)bx.psu.edu" from the database'
+ self.logout()
+ self.login( email='test3(a)bx.psu.edu' )
+ global regular_user3
+ regular_user3 = get_user( 'test3(a)bx.psu.edu' )
+ assert regular_user3 is not None, 'Problem retrieving user with email "test3(a)bx.psu.edu" from the database'
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
+ def test_005_create_library( self ):
+ """Testing creating a new library, then renaming it"""
+ # Logged in as admin_user
+ name = "library features Library1"
+ description = "library features Library1 description"
+ synopsis = "library features Library1 synopsis"
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ self.browse_libraries_admin( check_str1=name, check_str2=description )
+ # Get the library object for later tests
+ global library_one
+ library_one = get_library( name, description, synopsis )
+ assert library_one is not None, 'Problem retrieving library named "%s" from the database' % name
+ # Rename the library
+ new_name = "library features Library1 new name"
+ new_description = "library features Library1 new description"
+ new_synopsis = "library features Library1 new synopsis"
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ new_name=new_name,
+ new_description=new_description,
+ new_synopsis=new_synopsis )
+ self.browse_libraries_admin( check_str1=new_name, check_str2=new_description )
+ # Reset the library back to the original name and description
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ new_name=name,
+ new_description=description,
+ new_synopsis=synopsis )
+ refresh( library_one )
+ def test_010_library_template_features( self ):
+ """Testing adding a template to a library, then filling in the contents"""
+ # Logged in as admin_user
+ form_name = 'Library template Form One'
+ form_desc = 'This is Form One'
+ form_type = galaxy.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE
+ # Create form for library template
+ self.create_form( name=form_name, desc=form_desc, formtype=form_type )
+ global form_one
+ form_one = get_form( form_name )
+ assert form_one is not None, 'Problem retrieving form named (%s) from the database' % form_name
+ # Add new template based on the form to the library
+ template_name = 'Library Template 1'
+ self.add_library_template( 'library_admin',
+ 'library',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( form_one.id ),
+ form_one.name )
+ # Make sure the template fields are displayed on the library information page
+ field_dict = form_one.fields[ 0 ]
+ global form_one_field_label
+ form_one_field_label = '%s' % str( field_dict.get( 'label', 'Field 0' ) )
+ global form_one_field_help
+ form_one_field_help = '%s' % str( field_dict.get( 'helptext', 'Field 0 help' ) )
+ global form_one_field_required
+ form_one_field_required = '%s' % str( field_dict.get( 'required', 'optional' ) ).capitalize()
+ # Add information to the library using the template
+ global form_one_field_name
+ form_one_field_name = 'field_0'
+ contents = '%s library contents' % form_one_field_label
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ ele_1_field_name=form_one_field_name,
+ ele_1_contents=contents )
+ def test_015_edit_template_contents_admin_view( self ):
+ """Test editing template contents from the Admin view"""
+ # Logged in as admin_user
+ # Make sure the template contents were from the previous method correctly saved
+ # Twill barfs if this test is run in the previous method.
+ contents = '%s library contents' % form_one_field_label
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ check_str1=contents )
+ contents = '%s library contents' % form_one_field_label
+ contents_edited = contents + ' edited'
+ # Edit the contents and then save them
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ ele_1_field_name=form_one_field_name,
+ ele_1_contents=contents_edited )
+ # Make sure the template contents were correctly saved
+ self.library_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ check_str1=contents_edited )
+ def test_020_add_public_dataset_to_root_folder( self ):
+ """Testing adding a public dataset to the root folder, making sure library template is inherited"""
+ # Logged in as admin_user
+ message = 'Testing adding a public dataset to the root folder'
+ # The template should be inherited to the library dataset upload form.
+ template_contents = "%s contents for root folder 1.bed" % form_one_field_label
+ self.add_library_dataset( 'library_admin',
+ '1.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.root_folder.id ),
+ library_one.root_folder.name,
+ file_type='bed',
+ dbkey='hg18',
+ message=message.replace( ' ', '+' ),
+ root=True,
+ template_field_name1=form_one_field_name,
+ template_field_contents1=template_contents )
+ global ldda_one
+ ldda_one = get_latest_ldda()
+ assert ldda_one is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_one from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1='1.bed',
+ check_str2=message,
+ check_str3=admin_user.email )
+ # Make sure the library template contents were correctly saved
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.root_folder.id ),
+ self.security.encode_id( ldda_one.id ),
+ ldda_one.name,
+ check_str1=template_contents )
+ def test_025_add_new_folder_to_root_folder( self ):
+ """Testing adding a folder to a library root folder"""
+ # logged in as admin_user
+ root_folder = library_one.root_folder
+ name = "Root Folder's Folder One"
+ description = "This is the root folder's Folder One"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( root_folder.id ),
+ name=name,
+ description=description )
+ global folder_one
+ folder_one = get_folder( root_folder.id, name, description )
+ assert folder_one is not None, 'Problem retrieving library folder named "%s" from the database' % name
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=name,
+ check_str2=description )
+ # Make sure the template was inherited, but the contents were not
+ contents = '%s library contents' % form_one_field_label
+ self.folder_info( 'library_admin',
+ self.security.encode_id( folder_one.id ),
+ self.security.encode_id( library_one.id ),
+ check_str1=form_one_field_name,
+ not_displayed=contents )
+ # Add contents to the inherited template
+ template_contents = "%s contents for Folder One" % form_one_field_label
+ self.folder_info( 'library_admin',
+ self.security.encode_id( folder_one.id ),
+ self.security.encode_id( library_one.id ),
+ field_name=form_one_field_name,
+ contents=template_contents )
+ def test_030_add_subfolder_to_folder( self ):
+ """Testing adding a folder to a library folder"""
+ # logged in as admin_user
+ name = "Folder One's Subfolder"
+ description = "This is the Folder One's subfolder"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ name=name,
+ description=description )
+ global subfolder_one
+ subfolder_one = get_folder( folder_one.id, name, description )
+ assert subfolder_one is not None, 'Problem retrieving library folder named "Folder Ones Subfolder" from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=name,
+ check_str2=description )
+ # Make sure the template was inherited, but the contents were not
+ contents = '%s library contents' % form_one_field_label
+ self.folder_info( 'library_admin',
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( library_one.id ),
+ check_str1=form_one_field_name,
+ not_displayed=contents )
+ # Add contents to the inherited template
+ template_contents = "%s contents for Folder One" % form_one_field_label
+ self.folder_info( 'library_admin',
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( library_one.id ),
+ field_name=form_one_field_name,
+ contents=template_contents )
+ def test_035_add_2nd_new_folder_to_root_folder( self ):
+ """Testing adding a 2nd folder to a library root folder"""
+ # logged in as admin_user
+ root_folder = library_one.root_folder
+ name = "Folder Two"
+ description = "This is the root folder's Folder Two"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( root_folder.id ),
+ name=name,
+ description=description )
+ global folder_two
+ folder_two = get_folder( root_folder.id, name, description )
+ assert folder_two is not None, 'Problem retrieving library folder named "%s" from the database' % name
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=name,
+ check_str2=description )
+ def test_040_add_public_dataset_to_root_folders_2nd_subfolder( self ):
+ """Testing adding a public dataset to the root folder's 2nd sub-folder"""
+ # Logged in as admin_user
+ message = "Testing adding a public dataset to the folder named %s" % folder_two.name
+ # The form_one template should be inherited to the library dataset upload form.
+ template_contents = "%s contents for %s 2.bed" % ( form_one_field_label, folder_two.name )
+ self.add_library_dataset( 'library_admin',
+ '2.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ folder_two.name,
+ file_type='bed',
+ dbkey='hg18',
+ message=message.replace( ' ', '+' ),
+ root=False,
+ template_field_name1=form_one_field_name,
+ template_field_contents1=template_contents )
+ global ldda_two
+ ldda_two = get_latest_ldda()
+ assert ldda_two is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_two from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1='2.bed',
+ check_str2=message,
+ check_str3=admin_user.email )
+ # Make sure the library template contents were correctly saved
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ self.security.encode_id( ldda_two.id ),
+ ldda_two.name,
+ check_str1=template_contents )
+ def test_045_add_2nd_public_dataset_to_root_folders_2nd_subfolder( self ):
+ """Testing adding a 2nd public dataset to the root folder's 2nd sub-folder"""
+ # Logged in as admin_user
+ message = "Testing adding a 2nd public dataset to the folder named %s" % folder_two.name
+ # The form_one template should be inherited to the library dataset upload form.
+ template_contents = "%s contents for %s 3.bed" % ( form_one_field_label, folder_two.name )
+ self.add_library_dataset( 'library_admin',
+ '3.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ folder_two.name,
+ file_type='bed',
+ dbkey='hg18',
+ message=message.replace( ' ', '+' ),
+ root=False,
+ template_field_name1=form_one_field_name,
+ template_field_contents1=template_contents )
+ global ldda_three
+ ldda_three = get_latest_ldda()
+ assert ldda_three is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_three from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1='3.bed',
+ check_str2=message,
+ check_str3=admin_user.email )
+ # Make sure the library template contents were correctly saved
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ self.security.encode_id( ldda_three.id ),
+ ldda_three.name,
+ check_str1=template_contents )
+ def test_050_copy_dataset_from_history_to_subfolder( self ):
+ """Testing copying a dataset from the current history to a subfolder"""
+ # logged in as admin_user
+ self.new_history()
+ self.upload_file( "4.bed" )
+ latest_hda = get_latest_hda()
+ self.add_history_datasets_to_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ subfolder_one.name,
+ self.security.encode_id( latest_hda.id ),
+ root=False )
+ global ldda_four
+ ldda_four = get_latest_ldda()
+ assert ldda_four is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_four from the database'
+ # Make sure the correct template was inherited but the contents were not inherited
+ contents = "%s contents for Folder One's Subfolder" % form_one_field_label
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four.id ),
+ ldda_four.name,
+ check_str1=form_one_field_name,
+ not_displayed=contents )
+ def test_055_editing_dataset_attribute_info( self ):
+ """Testing editing a library dataset's attribute information"""
+ # logged in as admin_user
+ new_ldda_name = '4.bed ( version 1 )'
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four.id ),
+ ldda_four.name,
+ new_ldda_name=new_ldda_name )
+ refresh( ldda_four )
+ self.browse_library( 'library_admin', self.security.encode_id( library_one.id ), check_str1=new_ldda_name )
+ # Make sure the correct template was inherited but the contents were not inherited
+ contents = "%s contents for Folder One's Subfolder" % form_one_field_label
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four.id ),
+ ldda_four.name,
+ check_str1=form_one_field_name,
+ not_displayed=contents )
+ def test_060_uploading_new_dataset_version( self ):
+ """Testing uploading a new version of a library dataset"""
+ # logged in as admin_user
+ message = 'Testing uploading a new version of a dataset'
+ # The form_one template should be inherited to the library dataset upload form.
+ template_contents = "%s contents for %s new version of 4.bed" % ( form_one_field_label, folder_one.name )
+ self.upload_new_dataset_version( 'library_admin',
+ '4.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ subfolder_one.name,
+ self.security.encode_id( ldda_four.library_dataset.id ),
+ ldda_four.name,
+ file_type='auto',
+ dbkey='hg18',
+ message=message.replace( ' ', '+' ),
+ template_field_name1=form_one_field_name,
+ template_field_contents1=template_contents )
+ global ldda_four_version_two
+ ldda_four_version_two = get_latest_ldda()
+ assert ldda_four_version_two is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_four_version_two from the database'
+ # Make sure the correct template was inherited, but does not include any contents
+ contents = "%s contents for Folder One's Subfolder" % form_one_field_label
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four_version_two.id ),
+ ldda_four_version_two.name,
+ check_str1='This is the latest version of this library dataset',
+ not_displayed=contents )
+ # Fill in the template contents
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four_version_two.id ),
+ ldda_four_version_two.name,
+ ele_1_field_name=form_one_field_name,
+ ele_1_contents=template_contents )
+ # Check the previous version
+ self.ldda_edit_info( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( subfolder_one.id ),
+ self.security.encode_id( ldda_four.id ),
+ ldda_four.name,
+ check_str1='This is an expired version of this library dataset' )
+ # Make sure ldda_four is no longer displayed in the library
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ not_displayed=ldda_four.name )
+ def test_065_upload_directory_of_files_from_libraries_view( self ):
+ """Testing uploading a directory of files to a root folder from the Data Libraries view"""
+ # logged in as admin_user
+ # admin_user will not have the option to upload a directory of files from the
+ # Libraries view since a sub-directory named the same as their email is not contained
+ # in the configured user_library_import_dir. However, since members of role_one have
+ # the LIBRARY_ADD permission, we can test this feature as regular_user1 or regular_user3
+ self.logout()
+ self.login( email=regular_user1.email )
+ message = 'Uploaded all files in test-data/users/test1...'
+ # Since regular_user1 does not have any sub-directories contained within her configured
+ # user_library_import_dir, the only option in her server_dir select list will be the
+ # directory named the same as her email
+ check_str_after_submit = "Added 1 datasets to the library '%s' (each is selected)." % library_one.root_folder.name
+ # TODO: gvk( 3/12/10 )this is broken, so commenting until I have time to discover why...
+ """
+ self.upload_directory_of_files( 'library',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.root_folder.id ),
+ server_dir=regular_user1.email,
+ message=message,
+ check_str_after_submit=check_str_after_submit )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=regular_user1.email,
+ check_str2=message )
+ self.logout()
+ self.login( regular_user3.email )
+ message = 'Uploaded all files in test-data/users/test3.../run1'
+ # Since regular_user2 has a subdirectory contained within her configured user_library_import_dir,
+ # she will have a "None" option in her server_dir select list
+ self.upload_directory_of_files( 'library',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.root_folder.id ),
+ server_dir='run1',
+ message=message,
+ check_str1='<option>None</option>',
+ check_str_after_submit=check_str_after_submit )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=regular_user3.email,
+ check_str2=message )
+ """
+ def test_070_download_archive_of_library_files( self ):
+ """Testing downloading an archive of files from the library"""
+ # logged in as regular_user3
+ self.logout()
+ self.login( email=admin_user.email )
+ for format in ( 'tbz', 'tgz', 'zip' ):
+ archive = self.download_archive_of_library_files( cntrller='library',
+ library_id=self.security.encode_id( library_one.id ),
+ ldda_ids=[ self.security.encode_id( ldda_one.id ), self.security.encode_id( ldda_two.id ) ],
+ format=format )
+ self.check_archive_contents( archive, ( ldda_one, ldda_two ) )
+ os.remove( archive )
+ def test_075_mark_dataset_deleted( self ):
+ """Testing marking a library dataset as deleted"""
+ # Logged in as admin_user
+ self.delete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( ldda_two.library_dataset.id ),
+ ldda_two.name,
+ item_type='library_dataset' )
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ not_displayed=ldda_two.name )
+ def test_080_display_and_hide_deleted_dataset( self ):
+ """Testing displaying and hiding a deleted library dataset"""
+ # Logged in as admin_user
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ show_deleted=True,
+ check_str1=ldda_two.name )
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ not_displayed=ldda_two.name )
+ def test_085_mark_folder_deleted( self ):
+ """Testing marking a library folder as deleted"""
+ # Logged in as admin_user
+ self.delete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ folder_two.name,
+ item_type='folder' )
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ not_displayed=folder_two.name )
+ def test_090_mark_folder_undeleted( self ):
+ """Testing marking a library folder as undeleted"""
+ # Logged in as admin_user
+ self.undelete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ folder_two.name,
+ item_type='folder' )
+ # 2.bed was deleted before the folder was deleted, so state should have been saved. In order
+ # for 2.bed to be displayed, it would itself have to be marked undeleted.
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=folder_two.name,
+ not_displayed=ldda_two.name )
+ def test_095_mark_library_deleted( self ):
+ """Testing marking a library as deleted"""
+ # Logged in as admin_user
+ # First mark folder_two as deleted to further test state saving when we undelete the library
+ self.delete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_two.id ),
+ folder_two.name,
+ item_type='folder' )
+ self.delete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ item_type='library' )
+ self.browse_libraries_admin( not_displayed1=library_one.name )
+ self.browse_libraries_admin( deleted=True, check_str1=library_one.name )
+ def test_100_mark_library_undeleted( self ):
+ """Testing marking a library as undeleted"""
+ # Logged in as admin_user
+ self.undelete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ item_type='library' )
+ self.browse_libraries_admin( check_str1=library_one.name )
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=library_one.name,
+ not_displayed=folder_two.name )
+ def test_105_purge_library( self ):
+ """Testing purging a library"""
+ # Logged in as admin_user
+ self.delete_library_item( self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.id ),
+ library_one.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library_one.id ), library_one.name )
+ # Make sure the library was purged
+ refresh( library_one )
+ if not ( library_one.deleted and library_one.purged ):
+ raise AssertionError( 'The library id %s named "%s" has not been marked as deleted and purged.' % ( str( library_one.id ), library_one.name ) )
+ def check_folder( library_folder ):
+ for folder in library_folder.folders:
+ refresh( folder )
+ # Make sure all of the library_folders are purged
+ if not folder.purged:
+ raise AssertionError( 'The library_folder id %s named "%s" has not been marked purged.' % ( str( folder.id ), folder.name ) )
+ check_folder( folder )
+ # Make sure all of the LibraryDatasets and associated objects are deleted
+ refresh( library_folder )
+ for library_dataset in library_folder.datasets:
+ refresh( library_dataset )
+ ldda = library_dataset.library_dataset_dataset_association
+ if ldda:
+ refresh( ldda )
+ if not ldda.deleted:
+ raise AssertionError( 'The library_dataset_dataset_association id %s named "%s" has not been marked as deleted.' % \
+ ( str( ldda.id ), ldda.name ) )
+ # Make sure all of the datasets have been deleted
+ dataset = ldda.dataset
+ refresh( dataset )
+ if not dataset.deleted:
+ raise AssertionError( 'The dataset with id "%s" has not been marked as deleted when it should have been.' % \
+ str( ldda.dataset.id ) )
+ if not library_dataset.deleted:
+ raise AssertionError( 'The library_dataset id %s named "%s" has not been marked as deleted.' % \
+ ( str( library_dataset.id ), library_dataset.name ) )
+ check_folder( library_one.root_folder )
+ def test_110_no_library_template( self ):
+ """Test library features when library has no template"""
+ # Logged in as admin_user
+ name = "library features Library Two"
+ description = "library features This is Library Two"
+ synopsis = "library features Library Two synopsis"
+ # Create a library, adding no template
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ self.browse_libraries_admin( check_str1=name, check_str2=description )
+ global library_two
+ library_two = get_library( name, description, synopsis )
+ assert library_two is not None, 'Problem retrieving library named "%s" from the database' % name
+ # Add a dataset to the library
+ self.add_library_dataset( 'library_admin',
+ '3.bed',
+ self.security.encode_id( library_two.id ),
+ self.security.encode_id( library_two.root_folder.id ),
+ library_two.root_folder.name,
+ file_type='bed',
+ dbkey='hg18',
+ message='',
+ root=True )
+ ldda_three = get_latest_ldda()
+ assert ldda_three is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_three from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_two.id ),
+ check_str1='3.bed',
+ check_str2=admin_user.email )
+ # TODO: add a functional test to cover adding a library dataset via url_paste here...
+ # TODO: Add a functional test to cover checking the space_to_tab checkbox here...
+ # Delete and purge the library
+ self.delete_library_item( self.security.encode_id( library_two.id ),
+ self.security.encode_id( library_two.id ),
+ library_two.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library_two.id ), library_two.name )
+ self.home()
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
+ # Logged in as admin_user
+ ##################
+ # Purge all libraries
+ ##################
+ for library in [ library_one, library_two ]:
+ self.delete_library_item( self.security.encode_id( library.id ),
+ self.security.encode_id( library.id ),
+ library.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library.id ), library.name )
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 1 )' % ( len( user.roles ), user.email ) )
+ self.logout()
diff -r e39c9a2a0b4c -r 48e83411aa91 test/functional/test_library_security.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/functional/test_library_security.py Fri Mar 12 16:11:26 2010 -0500
@@ -0,0 +1,603 @@
+from base.twilltestcase import *
+from base.test_db_util import *
+
+class TestLibrarySecurity( TwillTestCase ):
+ def test_000_initiate_users( self ):
+ """Ensuring all required user accounts exist"""
+ self.logout()
+ self.login( email='test1(a)bx.psu.edu' )
+ global regular_user1
+ regular_user1 = get_user( 'test1(a)bx.psu.edu' )
+ assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
+ global regular_user1_private_role
+ regular_user1_private_role = get_private_role( regular_user1 )
+ self.logout()
+ self.login( email='test2(a)bx.psu.edu' )
+ global regular_user2
+ regular_user2 = get_user( 'test2(a)bx.psu.edu' )
+ assert regular_user2 is not None, 'Problem retrieving user with email "test2(a)bx.psu.edu" from the database'
+ global regular_user2_private_role
+ regular_user2_private_role = get_private_role( regular_user2 )
+ self.logout()
+ self.login( email='test3(a)bx.psu.edu' )
+ global regular_user3
+ regular_user3 = get_user( 'test3(a)bx.psu.edu' )
+ assert regular_user3 is not None, 'Problem retrieving user with email "test3(a)bx.psu.edu" from the database'
+ global regular_user3_private_role
+ regular_user3_private_role = get_private_role( regular_user3 )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ global admin_user
+ admin_user = get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
+ global admin_user_private_role
+ admin_user_private_role = get_private_role( admin_user )
+ def test_005_create_required_groups_and_roles( self ):
+ """Testing creating all required groups and roles for this script"""
+ # Logged in as admin_user
+ # Create role_one
+ name = 'library security Role One'
+ description = "library security This is Role One's description"
+ user_ids = [ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ]
+ self.create_role( name=name,
+ description=description,
+ in_user_ids=user_ids,
+ in_group_ids=[],
+ create_group_for_role='no',
+ private_role=admin_user.email )
+ # Get the role object for later tests
+ global role_one
+ role_one = get_role_by_name( name )
+ # Create group_one
+ name = 'Group One'
+ self.create_group( name=name, in_user_ids=[ str( regular_user1.id ) ], in_role_ids=[ str( role_one.id ) ] )
+ # Get the group object for later tests
+ global group_one
+ group_one = get_group_by_name( name )
+ assert group_one is not None, 'Problem retrieving group named "Group One" from the database'
+ # NOTE: To get this to work with twill, all select lists on the ~/admin/role page must contain at least
+ # 1 option value or twill throws an exception, which is: ParseError: OPTION outside of SELECT
+ # Due to this bug in twill, we create the role, we bypass the page and visit the URL in the
+ # associate_users_and_groups_with_role() method.
+ #
+ #create role_two
+ name = 'library security Role Two'
+ description = 'library security This is Role Two'
+ user_ids = [ str( admin_user.id ) ]
+ group_ids = [ str( group_one.id ) ]
+ private_role = admin_user.email
+ self.create_role( name=name,
+ description=description,
+ in_user_ids=user_ids,
+ in_group_ids=group_ids,
+ private_role=private_role )
+ # Get the role object for later tests
+ global role_two
+ role_two = get_role_by_name( name )
+ assert role_two is not None, 'Problem retrieving role named "Role Two" from the database'
+ def test_010_create_library( self ):
+ """Testing creating a new library, then renaming it"""
+ # Logged in as admin_user
+ name = "library security Library1"
+ description = "library security Library1 description"
+ synopsis = "library security Library1 synopsis"
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ # Get the library object for later tests
+ global library_one
+ library_one = get_library( name, description, synopsis )
+ assert library_one is not None, 'Problem retrieving library named "%s" from the database' % name
+ # Make sure library_one is public
+ assert 'access library' not in [ a.action for a in library_one.actions ], 'Library %s is not public when first created' % library_one.name
+ # Set permissions on the library, sort for later testing.
+ permissions_in = [ k for k, v in galaxy.model.Library.permitted_actions.items() ]
+ permissions_out = []
+ # Role one members are: admin_user, regular_user1, regular_user3. Each of these users will be permitted for
+ # LIBRARY_ACCESS, LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE on this library and it's contents.
+ self.library_permissions( self.security.encode_id( library_one.id ),
+ library_one.name,
+ str( role_one.id ),
+ permissions_in,
+ permissions_out )
+ # Make sure the library is accessible by admin_user
+ self.visit_url( '%s/library/browse_libraries' % self.url )
+ self.check_page_for_string( library_one.name )
+ # Make sure the library is not accessible by regular_user2 since regular_user2 does not have Role1.
+ self.logout()
+ self.login( email=regular_user2.email )
+ self.visit_url( '%s/library/browse_libraries' % self.url )
+ try:
+ self.check_page_for_string( library_one.name )
+ raise AssertionError, 'Library %s is accessible by %s when it should be restricted' % ( library_one.name, regular_user2.email )
+ except:
+ pass
+ self.logout()
+ self.login( email=admin_user.email )
+ def test_015_add_new_folder_to_root_folder( self ):
+ """Testing adding a folder to a library root folder"""
+ # logged in as admin_user
+ root_folder = library_one.root_folder
+ name = "Root Folder's Folder One"
+ description = "This is the root folder's Folder One"
+ self.add_folder( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( root_folder.id ),
+ name=name,
+ description=description )
+ global folder_one
+ folder_one = get_folder( root_folder.id, name, description )
+ assert folder_one is not None, 'Problem retrieving library folder named "%s" from the database' % name
+ def test_020_add_dataset_with_private_role_restriction_to_folder( self ):
+ """Testing adding a dataset with a private role restriction to a folder"""
+ # Logged in as admin_user
+ #
+ # Keep in mind that # LIBRARY_ACCESS = "Role One" on the whole library
+ #
+ # Add a dataset restricted by the following:
+ # DATASET_MANAGE_PERMISSIONS = "test(a)bx.psu.edu" via DefaultUserPermissions
+ # DATASET_ACCESS = "regular_user1" private role via this test method
+ # LIBRARY_ADD = "Role One" via inheritance from parent folder
+ # LIBRARY_MODIFY = "Role One" via inheritance from parent folder
+ # LIBRARY_MANAGE = "Role One" via inheritance from parent folder
+ # "Role One" members are: test(a)bx.psu.edu, test1(a)bx.psu.edu, test3(a)bx.psu.edu
+ # This means that only user test1(a)bx.psu.edu can see the dataset from the Libraries view
+ message ='This is a test of the fourth dataset uploaded'
+ self.add_library_dataset( 'library_admin',
+ '1.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ folder_one.name,
+ file_type='bed',
+ dbkey='hg18',
+ roles=[ str( regular_user1_private_role.id ) ],
+ message=message.replace( ' ', '+' ),
+ root=False )
+ global ldda_one
+ ldda_one = get_latest_ldda()
+ assert ldda_one is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_one from the database'
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1='1.bed',
+ check_str2=message,
+ check_str3=admin_user.email )
+ def test_025_accessing_dataset_with_private_role_restriction( self ):
+ """Testing accessing a dataset with a private role restriction"""
+ # Logged in as admin_user
+ #
+ # Keep in mind that # LIBRARY_ACCESS = "Role One" on the whole library
+ # Role one members are: admin_user, regular_user1, regular_user3. Each of these users will be permitted for
+ # LIBRARY_ACCESS, LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE on this library and it's contents.
+ #
+ # Legitimate roles displayed on the permission form are as follows:
+ # 'Role One' since the LIBRARY_ACCESS permission is associated with Role One. # Role one members are: admin_user, regular_user1, regular_user3.
+ # 'test(a)bx.psu.edu' ( admin_user's private role ) since admin_user has Role One
+ # 'Role Two' since admin_user has Role Two
+ # 'Role Three' since admin_user has Role Three
+ # 'test1(a)bx.psu.edu' ( regular_user1's private role ) since regular_user1 has Role One
+ # 'test3(a)bx.psu.edu' ( regular_user3's private role ) since regular_user3 has Role One
+ #
+ # admin_user should not be able to see 1.bed from the analysis view's access libraries
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ not_displayed=folder_one.name,
+ not_displayed2='1.bed' )
+ self.logout()
+ # regular_user1 should be able to see 1.bed from the analysis view's access librarys
+ # since it was associated with regular_user1's private role
+ self.login( email=regular_user1.email )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=folder_one.name,
+ check_str2='1.bed' )
+ self.logout()
+ # regular_user2 should not be to see the library since they do not have
+ # Role One which is associated with the LIBRARY_ACCESS permission
+ self.login( email=regular_user2.email )
+ self.browse_libraries_regular_user( check_str1="You are not authorized to access any libraries" )
+ self.logout()
+ # regular_user3 should not be able to see 1.bed from the analysis view's access librarys
+ self.login( email=regular_user3.email )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ not_displayed=folder_one.name,
+ not_displayed2='1.bed' )
+ self.logout()
+ self.login( email=admin_user.email )
+ def test_030_change_dataset_access_permission( self ):
+ """Testing changing the access permission on a dataset with a private role restriction"""
+ # Logged in as admin_user
+ # We need admin_user to be able to access 1.bed
+ permissions_in = [ k for k, v in galaxy.model.Dataset.permitted_actions.items() ]
+ for k, v in galaxy.model.Library.permitted_actions.items():
+ if k != 'LIBRARY_ACCESS':
+ permissions_in.append( k )
+ permissions_out = []
+ # Attempt to associate multiple roles with the library dataset, with one of the
+ # roles being private.
+ role_ids_str = '%s,%s' % ( str( role_one.id ), str( admin_user_private_role.id ) )
+ check_str = "At least 1 user must have every role associated with accessing datasets. "
+ check_str += "Since you are associating more than 1 role, no private roles are allowed."
+ self.ldda_permissions( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ self.security.encode_id( ldda_one.id ),
+ role_ids_str,
+ permissions_in,
+ permissions_out,
+ check_str1=check_str )
+ role_ids_str = str( role_one.id )
+ self.ldda_permissions( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ self.security.encode_id( ldda_one.id ),
+ role_ids_str,
+ permissions_in,
+ permissions_out )
+ # admin_user should now be able to see 1.bed from the analysis view's access libraries
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=ldda_one.name )
+ def test_035_add_dataset_with_role_associated_with_group_and_users( self ):
+ """Testing adding a dataset with a role that is associated with a group and users"""
+ # Logged in as admin_user
+ # Add a dataset restricted by role_two, which is currently associated as follows:
+ # groups: group_one
+ # users: test(a)bx.psu.edu, test1(a)bx.psu.edu via group_one
+ #
+ # We first need to make library_one public
+ permissions_in = []
+ for k, v in galaxy.model.Library.permitted_actions.items():
+ if k != 'LIBRARY_ACCESS':
+ permissions_in.append( k )
+ permissions_out = []
+ # Role one members are: admin_user, regular_user1, regular_user3. Each of these users will now be permitted for
+ # LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE on this library and it's contents. The library will be public from
+ # this point on.
+ self.library_permissions( self.security.encode_id( library_one.id ),
+ library_one.name,
+ str( role_one.id ),
+ permissions_in,
+ permissions_out )
+ refresh( library_one )
+ message = 'Testing adding a dataset with a role that is associated with a group and users'
+ self.add_library_dataset( 'library_admin',
+ '2.bed',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ folder_one.name,
+ file_type='bed',
+ dbkey='hg17',
+ roles=[ str( role_two.id ) ],
+ message=message.replace( ' ', '+' ),
+ root=False )
+ global ldda_two
+ ldda_two = get_latest_ldda()
+ assert ldda_two is not None, 'Problem retrieving LibraryDatasetDatasetAssociation ldda_two from the database'
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1='2.bed',
+ check_str2=message,
+ check_str3=admin_user.email )
+ def test_040_accessing_dataset_with_role_associated_with_group_and_users( self ):
+ """Testing accessing a dataset with a role that is associated with a group and users"""
+ # Logged in as admin_user
+ # admin_user should be able to see 2.bed since she is associated with role_two
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1='2.bed',
+ check_str2=admin_user.email )
+ self.logout()
+ # regular_user1 should be able to see 2.bed since she is associated with group_two
+ self.login( email = 'test1(a)bx.psu.edu' )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=folder_one.name,
+ check_str2='2.bed',
+ check_str3=admin_user.email )
+ # Check the permissions on the dataset 2.bed - they are as folows:
+ # DATASET_MANAGE_PERMISSIONS = test(a)bx.psu.edu
+ # DATASET_ACCESS = Role Two
+ # Role Two associations: test(a)bx.psu.edu and Group Two
+ # Group Two members: Role One, Role Two, test1(a)bx.psu.edu
+ # Role One associations: test(a)bx.psu.edu, test1(a)bx.psu.edu, test3(a)bx.psu.edu
+ # LIBRARY_ADD = Role One
+ # Role One aassociations: test(a)bx.psu.edu, test1(a)bx.psu.edu, test3(a)bx.psu.edu
+ # LIBRARY_MODIFY = Role One
+ # Role One aassociations: test(a)bx.psu.edu, test1(a)bx.psu.edu, test3(a)bx.psu.edu
+ # LIBRARY_MANAGE = Role One
+ # Role One aassociations: test(a)bx.psu.edu, test1(a)bx.psu.edu, test3(a)bx.psu.edu
+ self.ldda_edit_info( 'library',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ self.security.encode_id( ldda_two.id ),
+ ldda_two.name,
+ check_str1='2.bed',
+ check_str2='This is the latest version of this library dataset',
+ check_str3='Edit attributes of 2.bed' )
+ self.act_on_multiple_datasets( 'library',
+ self.security.encode_id( library_one.id ),
+ 'import_to_history',
+ ldda_ids=self.security.encode_id( ldda_two.id ),
+ check_str1='1 dataset(s) have been imported into your history' )
+ self.logout()
+ # regular_user2 should not be able to see 2.bed
+ self.login( email = 'test2(a)bx.psu.edu' )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ not_displayed=folder_one.name,
+ not_displayed2='2.bed' )
+
+ self.logout()
+ # regular_user3 should not be able to see folder_one ( even though it does not contain any datasets that she
+ # can access ) since she has Role One, and Role One has all library permissions ( see above ).
+ self.login( email = 'test3(a)bx.psu.edu' )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ check_str1=folder_one.name,
+ not_displayed='2.bed' )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ def test_045_upload_directory_of_files_from_admin_view( self ):
+ """Testing uploading a directory of files to a root folder from the Admin view"""
+ # logged in as admin_user
+ message = 'This is a test for uploading a directory of files'
+ check_str_after_submit="Added 3 datasets to the library '%s' (each is selected)." % library_one.root_folder.name
+ self.upload_directory_of_files( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( library_one.root_folder.id ),
+ server_dir='library',
+ message=message,
+ check_str_after_submit=check_str_after_submit )
+ self.browse_library( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ check_str1=admin_user.email,
+ check_str2=message )
+ def test_050_change_permissions_on_datasets_uploaded_from_library_dir( self ):
+ """Testing changing the permissions on datasets uploaded from a directory from the Admin view"""
+ # logged in as admin_user
+ # It would be nice if twill functioned such that the above test resulted in a
+ # form with the uploaded datasets selected, but it does not ( they're not checked ),
+ # so we'll have to simulate this behavior ( not ideal ) for the 'edit' action. We
+ # first need to get the ldda.id for the 3 new datasets
+ latest_3_lddas = get_latest_lddas( 3 )
+ ldda_ids = ''
+ for ldda in latest_3_lddas:
+ ldda_ids += '%s,' % self.security.encode_id( ldda.id )
+ ldda_ids = ldda_ids.rstrip( ',' )
+ # Set permissions
+ self.ldda_permissions( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ ldda_ids,
+ str( role_one.id ),
+ permissions_in=[ 'DATASET_ACCESS', 'LIBRARY_MANAGE' ],
+ check_str1='Permissions have been updated on 3 datasets' )
+ # Make sure the permissions have been correctly updated for the 3 datasets. Permissions should
+ # be all of the above on any of the 3 datasets that are imported into a history.
+ def check_edit_page( lddas, check_str1='', check_str2='', check_str3='', check_str4='',
+ not_displayed1='', not_displayed2='', not_displayed3='' ):
+ for ldda in lddas:
+ # Import each library dataset into our history
+ self.act_on_multiple_datasets( 'library',
+ self.security.encode_id( library_one.id ),
+ 'import_to_history',
+ ldda_ids=self.security.encode_id( ldda.id ) )
+ # Determine the new HistoryDatasetAssociation id created when the library dataset was imported into our history
+ last_hda_created = get_latest_hda()
+ self.edit_hda_attribute_info( str( last_hda_created.id ),
+ check_str1=check_str1,
+ check_str2=check_str2,
+ check_str3=check_str3,
+ check_str4=check_str4 )
+ # admin_user is associated with role_one, so should have all permissions on imported datasets
+ check_edit_page( latest_3_lddas,
+ check_str1='Manage dataset permissions on',
+ check_str2='Role members can manage the roles associated with permissions on this dataset',
+ check_str3='Role members can import this dataset into their history for analysis' )
+ self.logout()
+ # regular_user1 is associated with role_one, so should have all permissions on imported datasets
+ self.login( email='test1(a)bx.psu.edu' )
+ check_edit_page( latest_3_lddas )
+ self.logout()
+ # Since regular_user2 is not associated with role_one, she should not have
+ # access to any of the 3 datasets, so she will not see folder_one on the libraries page
+ self.login( email='test2(a)bx.psu.edu' )
+ self.browse_library( 'library',
+ self.security.encode_id( library_one.id ),
+ not_displayed=folder_one.name )
+ self.logout()
+ # regular_user3 is associated with role_one, so should have all permissions on imported datasets
+ self.login( email='test3(a)bx.psu.edu' )
+ check_edit_page( latest_3_lddas )
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ # Change the permissions and test again
+ self.ldda_permissions( 'library_admin',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( folder_one.id ),
+ ldda_ids,
+ str( role_one.id ),
+ permissions_in=[ 'DATASET_ACCESS' ],
+ check_str1='Permissions have been updated on 3 datasets' )
+ check_edit_page( latest_3_lddas,
+ check_str1='View Permissions',
+ not_displayed1='Manage dataset permissions on',
+ not_displayed2='Role members can manage roles associated with permissions on this library item',
+ not_displayed3='Role members can import this dataset into their history for analysis' )
+ def test_055_library_permissions( self ):
+ """Test library permissions"""
+ # Logged in as admin_user
+ form_name = 'Library template Form One'
+ form_desc = 'This is Form One'
+ form_type = galaxy.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE
+ # Create form for library template
+ self.create_form( name=form_name, desc=form_desc, formtype=form_type )
+ global form_one
+ form_one = get_form( form_name )
+ assert form_one is not None, 'Problem retrieving form named (%s) from the database' % form_name
+ # Make sure the template fields are displayed on the library information page
+ field_dict = form_one.fields[ 0 ]
+ global form_one_field_label
+ form_one_field_label = '%s' % str( field_dict.get( 'label', 'Field 0' ) )
+ global form_one_field_help
+ form_one_field_help = '%s' % str( field_dict.get( 'helptext', 'Field 0 help' ) )
+ global form_one_field_required
+ form_one_field_required = '%s' % str( field_dict.get( 'required', 'optional' ) ).capitalize()
+ # Add information to the library using the template
+ global form_one_field_name
+ form_one_field_name = 'field_0'
+ # Create a library, adding no template
+ name = "library security Library Two"
+ description = "library security This is Library Two"
+ synopsis = "library security Library Two synopsis"
+ self.create_library( name=name, description=description, synopsis=synopsis )
+ self.browse_libraries_admin( check_str1=name, check_str2=description )
+ global library_two
+ library_two = get_library( name, description, synopsis )
+ assert library_two is not None, 'Problem retrieving library named "%s" from the database' % name
+ # Set library permissions for regular_user1 and regular_user2. Each of these users will be permitted to
+ # LIBRARY_ADD, LIBRARY_MODIFY, LIBRARY_MANAGE for library items.
+ permissions_in = [ k for k, v in galaxy.model.Library.permitted_actions.items() ]
+ permissions_out = []
+ role_ids_str = '%s,%s' % ( str( regular_user1_private_role.id ), str( regular_user2_private_role.id ) )
+ self.library_permissions( self.security.encode_id( library_two.id ),
+ library_two.name,
+ role_ids_str,
+ permissions_in,
+ permissions_out )
+ self.logout()
+ # Login as regular_user1 and make sure they can see the library
+ self.login( email=regular_user1.email )
+ self.browse_libraries_regular_user( check_str1=name )
+ self.logout()
+ # Login as regular_user2 and make sure they can see the library
+ self.login( email=regular_user2.email )
+ self.browse_libraries_regular_user( check_str1=name )
+ # Add a dataset to the library
+ message = 'Testing adding 1.bed to Library Two root folder'
+ self.add_library_dataset( 'library',
+ '1.bed',
+ self.security.encode_id( library_two.id ),
+ self.security.encode_id( library_two.root_folder.id ),
+ library_two.root_folder.name,
+ file_type='bed',
+ dbkey='hg18',
+ message=message,
+ root=True )
+ # Add a folder to the library
+ name = "Root Folder's Folder X"
+ description = "This is the root folder's Folder X"
+ self.add_folder( 'library',
+ self.security.encode_id( library_two.id ),
+ self.security.encode_id( library_two.root_folder.id ),
+ name=name,
+ description=description )
+ global folder_x
+ folder_x = get_folder( library_two.root_folder.id, name, description )
+ # Add an information template to the folder
+ template_name = 'Folder Template 1'
+ self.add_library_template( 'library',
+ 'folder',
+ self.security.encode_id( library_one.id ),
+ self.security.encode_id( form_one.id ),
+ form_one.name,
+ folder_id=self.security.encode_id( folder_x.id ) )
+ # Modify the folder's information
+ contents = '%s folder contents' % form_one_field_label
+ new_name = "Root Folder's Folder Y"
+ new_description = "This is the root folder's Folder Y"
+ self.folder_info( 'library',
+ self.security.encode_id( folder_x.id ),
+ self.security.encode_id( library_two.id ),
+ name,
+ new_name,
+ new_description,
+ contents=contents,
+ field_name=form_one_field_name )
+ # Twill barfs when self.check_page_for_string() is called after dealing with an information template,
+ # the exception is: TypeError: 'str' object is not callable
+ # the work-around it to end this method so any calls are in the next method.
+ def test_060_template_features_and_permissions( self ):
+ """Test library template and more permissions behavior from the Data Libraries view"""
+ # Logged in as regular_user2
+ refresh( folder_x )
+ # Add a dataset to the folder
+ message = 'Testing adding 2.bed to Library Three root folder'
+ self.add_library_dataset( 'library',
+ '2.bed',
+ self.security.encode_id( library_two.id ),
+ self.security.encode_id( folder_x.id ),
+ folder_x.name,
+ file_type='bed',
+ dbkey='hg18',
+ message=message.replace( ' ', '+' ),
+ root=False )
+ global ldda_x
+ ldda_x = get_latest_ldda()
+ assert ldda_x is not None, 'Problem retrieving ldda_x from the database'
+ # Add an information template to the library
+ template_name = 'Library Template 3'
+ self.add_library_template( 'library',
+ 'library',
+ self.security.encode_id( library_two.id ),
+ self.security.encode_id( form_one.id ),
+ form_one.name )
+ # Add information to the library using the template
+ contents = '%s library contents' % form_one_field_label
+ self.visit_url( '%s/library_common/library_info?cntrller=library&id=%s' % ( self.url, self.security.encode_id( library_two.id ) ) )
+ # There are 2 forms on this page and the template is the 2nd form
+ tc.fv( '2', form_one_field_name, contents )
+ tc.submit( 'edit_info_button' )
+ # For some reason, the following check:
+ # self.check_page_for_string ( 'The information has been updated.' )
+ # ...throws the following exception - I have not idea why!
+ # TypeError: 'str' object is not callable
+ # The work-around is to not make ANY self.check_page_for_string() calls until the next method
+ def test_065_permissions_as_different_regular_user( self ):
+ """Test library template and more permissions behavior from the Data Libraries view as a different user"""
+ # Logged in as regular_user2
+ self.logout()
+ self.login( email=regular_user1.email )
+ self.browse_library( 'library',
+ self.security.encode_id( library_two.id ),
+ check_str1=ldda_x.name )
+ def test_999_reset_data_for_later_test_runs( self ):
+ """Reseting data to enable later test runs to pass"""
+ # Logged in as regular_user1
+ self.logout()
+ self.login( email=admin_user.email )
+ ##################
+ # Purge all libraries
+ ##################
+ for library in [ library_one, library_two ]:
+ self.delete_library_item( self.security.encode_id( library.id ),
+ self.security.encode_id( library.id ),
+ library.name,
+ item_type='library' )
+ self.purge_library( self.security.encode_id( library.id ), library.name )
+ ##################
+ # Eliminate all non-private roles
+ ##################
+ for role in [ role_one, role_two ]:
+ self.mark_role_deleted( self.security.encode_id( role.id ), role.name )
+ self.purge_role( self.security.encode_id( role.id ), role.name )
+ # Manually delete the role from the database
+ refresh( role )
+ sa_session.delete( role )
+ sa_session.flush()
+ ##################
+ # Eliminate all groups
+ ##################
+ for group in [ group_one ]:
+ self.mark_group_deleted( self.security.encode_id( group.id ), group.name )
+ self.purge_group( self.security.encode_id( group.id ), group.name )
+ # Manually delete the group from the database
+ refresh( group )
+ sa_session.delete( group )
+ sa_session.flush()
+ ##################
+ # Make sure all users are associated only with their private roles
+ ##################
+ for user in [ admin_user, regular_user1, regular_user2, regular_user3 ]:
+ refresh( user )
+ if len( user.roles) != 1:
+ raise AssertionError( '%d UserRoleAssociations are associated with %s ( should be 1 )' % ( len( user.roles ), user.email ) )
diff -r e39c9a2a0b4c -r 48e83411aa91 test/functional/test_security_and_libraries.py
--- a/test/functional/test_security_and_libraries.py Fri Mar 12 14:27:04 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2141 +0,0 @@
-import galaxy.model
-from galaxy.model.orm import *
-from galaxy.model.mapping import context as sa_session
-from base.twilltestcase import *
-
-not_logged_in_security_msg = 'You must be logged in as an administrator to access this feature.'
-logged_in_security_msg = 'You must be an administrator to access this feature.'
-
-import sys
-class TestSecurityAndLibraries( TwillTestCase ):
- def test_000_admin_features_when_not_logged_in( self ):
- """Testing admin_features when not logged in"""
- self.logout()
- self.visit_url( "%s/admin" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/reload_tool?tool_id=upload1" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/roles" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/create_role" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/create_role" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/manage_users_and_groups_for_role" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/groups" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/create_group" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- self.check_page_for_string( not_logged_in_security_msg )
- self.visit_url( "%s/admin/users" % self.url )
- self.check_page_for_string( not_logged_in_security_msg )
- def test_005_login_as_admin_user( self ):
- """Testing logging in as an admin user test(a)bx.psu.edu - tests initial settings for DefaultUserPermissions and DefaultHistoryPermissions"""
- self.login( email='test(a)bx.psu.edu' ) # test(a)bx.psu.edu is configured as our admin user
- self.visit_page( "admin" )
- self.check_page_for_string( 'Administration' )
- global admin_user
- admin_user = sa_session.query( galaxy.model.User ) \
- .filter( galaxy.model.User.table.c.email=='test(a)bx.psu.edu' ) \
- .first()
- assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
- # Get the admin user's private role for later use
- global admin_user_private_role
- admin_user_private_role = None
- for role in admin_user.all_roles():
- if role.name == admin_user.email and role.description == 'Private Role for %s' % admin_user.email:
- admin_user_private_role = role
- break
- if not admin_user_private_role:
- raise AssertionError( "Private role not found for user '%s'" % admin_user.email )
- # Make sure DefaultUserPermissions are correct
- if len( admin_user.default_permissions ) > 1:
- raise AssertionError( '%d DefaultUserPermissions associated with user %s ( should be 1 )' \
- % ( len( admin_user.default_permissions ), admin_user.email ) )
- dup = sa_session.query( galaxy.model.DefaultUserPermissions ) \
- .filter( galaxy.model.DefaultUserPermissions.table.c.user_id==admin_user.id ) \
- .first()
- if not dup.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
- raise AssertionError( 'The DefaultUserPermission.action for user "%s" is "%s", but it should be "%s"' \
- % ( admin_user.email, dup.action, galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
- # Make sure DefaultHistoryPermissions are correct
- # Logged in as admin_user
- latest_history = sa_session.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.deleted==False,
- galaxy.model.History.table.c.user_id==admin_user.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- if len( latest_history.default_permissions ) > 1:
- raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d when it was created ( should have been 1 )' \
- % ( len( latest_history.default_permissions ), latest_history.id ) )
- dhp = sa_session.query( galaxy.model.DefaultHistoryPermissions ) \
- .filter( galaxy.model.DefaultHistoryPermissions.table.c.history_id==latest_history.id ) \
- .first()
- if not dhp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
- raise AssertionError( 'The DefaultHistoryPermission.action for history id %d is "%s", but it should be "%s"' \
- % ( latest_history.id, dhp.action, galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
- self.home()
- self.visit_url( "%s/admin/manage_roles_and_groups_for_user?id=%s" % ( self.url, self.security.encode_id( admin_user.id ) ) )
- self.check_page_for_string( admin_user.email )
- # Try deleting the admin_user's private role
- check_str = "You cannot eliminate a user's private role association."
- self.associate_roles_and_groups_with_user( self.security.encode_id( admin_user.id ), admin_user.email,
- out_role_ids=str( admin_user_private_role.id ),
- check_str=check_str )
- self.logout()
- def test_010_login_as_regular_user1( self ):
- """Testing logging in as regular user test1(a)bx.psu.edu - tests private role creation and changing DefaultHistoryPermissions for new histories"""
- # Some of the history related tests here are similar to some tests in the
- # test_history_functions.py script, so we could potentially eliminate 1 or 2 of them.
- self.login( email='test1(a)bx.psu.edu' ) # test1(a)bx.psu.edu is not an admin user
- global regular_user1
- regular_user1 = sa_session.query( galaxy.model.User ) \
- .filter( galaxy.model.User.table.c.email=='test1(a)bx.psu.edu' ) \
- .first()
- assert regular_user1 is not None, 'Problem retrieving user with email "test1(a)bx.psu.edu" from the database'
- self.visit_page( "admin" )
- self.check_page_for_string( logged_in_security_msg )
- # Make sure a private role exists for regular_user1
- private_role = None
- for role in regular_user1.all_roles():
- if role.name == regular_user1.email and role.description == 'Private Role for %s' % regular_user1.email:
- private_role = role
- break
- if not private_role:
- raise AssertionError( "Private role not found for user '%s'" % regular_user1.email )
- global regular_user1_private_role
- regular_user1_private_role = private_role
- # Add a dataset to the history
- self.upload_file( '1.bed' )
- latest_dataset = sa_session.query( galaxy.model.Dataset ) \
- .order_by( desc( galaxy.model.Dataset.table.c.create_time ) ) \
- .first()
- # Make sure DatasetPermissions is correct - default is 'manage permissions'
- if len( latest_dataset.actions ) > 1:
- actions = [ a.action for a in latest_dataset.actions ]
- raise AssertionError( '%d DatasetPermissions (%s) were created for dataset id %d when it was created ( should have been 1 )' \
- % ( len( latest_dataset.actions ), str( actions ), latest_dataset.id ) )
- dp = sa_session.query( galaxy.model.DatasetPermissions ) \
- .filter( galaxy.model.DatasetPermissions.table.c.dataset_id==latest_dataset.id ) \
- .first()
- if not dp.action:
- raise AssertionError( 'The Dataset id %d has no associated DatasetPermissions when is should have "manage permissions".' \
- % latest_dataset.id )
- elif not dp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
- raise AssertionError( 'The DatasetPermissions.action for dataset id %d is "%s", but it should be "manage permissions"' \
- % ( latest_dataset.id, dp.action ) )
- # Change DefaultHistoryPermissions for regular_user1
- permissions_in = []
- actions_in = []
- for key, value in galaxy.model.Dataset.permitted_actions.items():
- # NOTE: setting the 'access' permission with the private role makes this dataset private
- permissions_in.append( key )
- actions_in.append( value.action )
- # Sort actions for later comparison
- actions_in.sort()
- role_id = str( private_role.id )
- self.user_set_default_permissions( permissions_in=permissions_in, role_id=role_id )
- # Make sure the default permissions are changed for new histories
- self.new_history()
- # logged in as regular_user1
- latest_history = sa_session.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.deleted==False,
- galaxy.model.History.table.c.user_id==regular_user1.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- if len( latest_history.default_permissions ) != len( galaxy.model.Dataset.permitted_actions.items() ):
- raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d, should have been %d' % \
- ( len( latest_history.default_permissions ), latest_history.id, len( galaxy.model.Dataset.permitted_actions.items() ) ) )
- dhps = []
- for dhp in latest_history.default_permissions:
- dhps.append( dhp.action )
- # Sort permissions for later comparison
- dhps.sort()
- for key, value in galaxy.model.Dataset.permitted_actions.items():
- if value.action not in dhps:
- raise AssertionError( '%s not in history id %d default_permissions after they were changed' % ( value.action, latest_history.id ) )
- # Add a dataset to the history
- self.upload_file( '1.bed' )
- latest_dataset = sa_session.query( galaxy.model.Dataset ).order_by( desc( galaxy.model.Dataset.table.c.create_time ) ).first()
- # Make sure DatasetPermissionss are correct
- if len( latest_dataset.actions ) != len( latest_history.default_permissions ):
- raise AssertionError( '%d DatasetPermissionss were created for dataset id %d when it was created ( should have been %d )' % \
- ( len( latest_dataset.actions ), latest_dataset.id, len( latest_history.default_permissions ) ) )
- dps = []
- for dp in latest_dataset.actions:
- dps.append( dp.action )
- # Sort actions for later comparison
- dps.sort()
- # Compare DatasetPermissions with permissions_in - should be the same
- if dps != actions_in:
- raise AssertionError( 'DatasetPermissionss "%s" for dataset id %d differ from changed default permissions "%s"' \
- % ( str( dps ), latest_dataset.id, str( actions_in ) ) )
- # Compare DefaultHistoryPermissions and DatasetPermissionss - should be the same
- if dps != dhps:
- raise AssertionError( 'DatasetPermissionss "%s" for dataset id %d differ from DefaultHistoryPermissions "%s" for history id %d' \
- % ( str( dps ), latest_dataset.id, str( dhps ), latest_history.id ) )
- self.logout()
-
- def test_015_login_as_regular_user2( self ):
- """Testing logging in as regular user test2(a)bx.psu.edu - tests changing DefaultHistoryPermissions for the current history"""
- email = 'test2(a)bx.psu.edu'
- self.login( email=email ) # This will not be an admin user
- global regular_user2
- regular_user2 = sa_session.query( galaxy.model.User ) \
- .filter( galaxy.model.User.table.c.email==email ) \
- .first()
- assert regular_user2 is not None, 'Problem retrieving user with email "" from the database' % email
- # Logged in as regular_user2
- latest_history = sa_session.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.deleted==False,
- galaxy.model.History.table.c.user_id==regular_user2.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- self.upload_file( '1.bed' )
- latest_dataset = sa_session.query( galaxy.model.Dataset ).order_by( desc( galaxy.model.Dataset.table.c.create_time ) ).first()
- permissions_in = [ 'DATASET_MANAGE_PERMISSIONS' ]
- # Make sure these are in sorted order for later comparison
- actions_in = [ 'manage permissions' ]
- permissions_out = [ 'DATASET_ACCESS' ]
- actions_out = [ 'access' ]
- global regular_user2_private_role
- regular_user2_private_role = None
- for role in regular_user2.all_roles():
- if role.name == regular_user2.email and role.description == 'Private Role for %s' % regular_user2.email:
- regular_user2_private_role = role
- break
- if not regular_user2_private_role:
- raise AssertionError( "Private role not found for user '%s'" % regular_user2.email )
- role_id = str( regular_user2_private_role.id )
- # Change DefaultHistoryPermissions for the current history
- self.history_set_default_permissions( permissions_out=permissions_out, permissions_in=permissions_in, role_id=role_id )
- if len( latest_history.default_permissions ) != len( actions_in ):
- raise AssertionError( '%d DefaultHistoryPermissions were created for history id %d, should have been %d' \
- % ( len( latest_history.default_permissions ), latest_history.id, len( permissions_in ) ) )
- # Make sure DefaultHistoryPermissions were correctly changed for the current history
- dhps = []
- for dhp in latest_history.default_permissions:
- dhps.append( dhp.action )
- # Sort permissions for later comparison
- dhps.sort()
- # Compare DefaultHistoryPermissions and actions_in - should be the same
- if dhps != actions_in:
- raise AssertionError( 'DefaultHistoryPermissions "%s" for history id %d differ from actions "%s" passed for changing' \
- % ( str( dhps ), latest_history.id, str( actions_in ) ) )
- # Make sure DatasetPermissionss are correct
- if len( latest_dataset.actions ) != len( latest_history.default_permissions ):
- raise AssertionError( '%d DatasetPermissionss were created for dataset id %d when it was created ( should have been %d )' \
- % ( len( latest_dataset.actions ), latest_dataset.id, len( latest_history.default_permissions ) ) )
- dps = []
- for dp in latest_dataset.actions:
- dps.append( dp.action )
- # Sort actions for comparison
- dps.sort()
- # Compare DatasetPermissionss and DefaultHistoryPermissions - should be the same
- if dps != dhps:
- raise AssertionError( 'DatasetPermissionss "%s" for dataset id %d differ from DefaultHistoryPermissions "%s"' \
- % ( str( dps ), latest_dataset.id, str( dhps ) ) )
- self.logout()
- def test_020_create_new_user_account_as_admin( self ):
- """Testing creating a new user account as admin"""
- self.login( email=admin_user.email )
- email = 'test3(a)bx.psu.edu'
- password = 'testuser'
- previously_created = self.create_new_account_as_admin( email=email, password=password )
- # Get the user object for later tests
- global regular_user3
- regular_user3 = sa_session.query( galaxy.model.User ).filter( galaxy.model.User.table.c.email==email ).first()
- assert regular_user3 is not None, 'Problem retrieving user with email "%s" from the database' % email
- global regular_user3_private_role
- regular_user3_private_role = None
- for role in regular_user3.all_roles():
- if role.name == regular_user3.email and role.description == 'Private Role for %s' % regular_user3.email:
- regular_user3_private_role = role
- break
- if not regular_user3_private_role:
- raise AssertionError( "Private role not found for user '%s'" % regular_user3.email )
- # Make sure DefaultUserPermissions were created
- if not regular_user3.default_permissions:
- raise AssertionError( 'No DefaultUserPermissions were created for user %s when the admin created the account' % email )
- # Make sure a private role was created for the user
- if not regular_user3.roles:
- raise AssertionError( 'No UserRoleAssociations were created for user %s when the admin created the account' % email )
- if not previously_created and len( regular_user3.roles ) != 1:
- raise AssertionError( '%d UserRoleAssociations were created for user %s when the admin created the account ( should have been 1 )' \
- % ( len( regular_user3.roles ), regular_user3.email ) )
- for ura in regular_user3.roles:
- role = sa_session.query( galaxy.model.Role ).get( ura.role_id )
- if not previously_created and role.type != 'private':
- raise AssertionError( 'Role created for user %s when the admin created the account is not private, type is' \
- % str( role.type ) )
- if not previously_created:
- # Make sure a history was not created ( previous test runs may have left deleted histories )
- histories = sa_session.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.user_id==regular_user3.id,
- galaxy.model.History.table.c.deleted==False ) ) \
- .all()
- if histories:
- raise AssertionError( 'Histories were incorrectly created for user %s when the admin created the account' % email )
- # Make sure the user was not associated with any groups
- if regular_user3.groups:
- raise AssertionError( 'Groups were incorrectly associated with user %s when the admin created the account' % email )
- def test_025_reset_password_as_admin( self ):
- """Testing reseting a user password as admin"""
- email = 'test3(a)bx.psu.edu'
- self.reset_password_as_admin( user_id=self.security.encode_id( regular_user3.id ), password='testreset' )
- self.logout()
- def test_030_login_after_password_reset( self ):
- """Testing logging in after an admin reset a password - tests DefaultHistoryPermissions for accounts created by an admin"""
- self.login( email='test3(a)bx.psu.edu', password='testreset' )
- # Make sure a History and HistoryDefaultPermissions exist for the user
- # Logged in as regular_user3
- latest_history = sa_session.query( galaxy.model.History ) \
- .filter( and_( galaxy.model.History.table.c.deleted==False,
- galaxy.model.History.table.c.user_id==regular_user3.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- if not latest_history.user_id == regular_user3.id:
- raise AssertionError( 'A history was not created for user %s when he logged in' % email )
- if not latest_history.default_permissions:
- raise AssertionError( 'No DefaultHistoryPermissions were created for history id %d when it was created' % latest_history.id )
- if len( latest_history.default_permissions ) > 1:
- raise AssertionError( 'More than 1 DefaultHistoryPermissions were created for history id %d when it was created' % latest_history.id )
- dhp = sa_session.query( galaxy.model.DefaultHistoryPermissions ) \
- .filter( galaxy.model.DefaultHistoryPermissions.table.c.history_id==latest_history.id ) \
- .first()
- if not dhp.action == galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
- raise AssertionError( 'The DefaultHistoryPermission.action for history id %d is "%s", but it should be "manage permissions"' \
- % ( latest_history.id, dhp.action ) )
- # Upload a file to create a HistoryDatasetAssociation
- self.upload_file( '1.bed' )
- latest_dataset = sa_session.query( galaxy.model.Dataset ).order_by( desc( galaxy.model.Dataset.table.c.create_time ) ).first()
- for dp in latest_dataset.actions:
- # Should only have 1 DatasetPermissions
- if dp.action != galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action:
- raise AssertionError( 'The DatasetPermissions for dataset id %d is %s ( should have been %s )' \
- % ( latest_dataset.id,
- latest_dataset.actions.action,
- galaxy.model.Dataset.permitted_actions.DATASET_MANAGE_PERMISSIONS.action ) )
- self.logout()
- # Reset the password to the default for later tests
- self.login( email='test(a)bx.psu.edu' )
- self.reset_password_as_admin( user_id=self.security.encode_id( regular_user3.id ), password='testuser' )
- def test_035_mark_user_deleted( self ):
- """Testing marking a user account as deleted"""
- # Logged in as admin_user
- self.mark_user_deleted( user_id=self.security.encode_id( regular_user3.id ), email=regular_user3.email )
- # Deleting a user should not delete any associations
- sa_session.refresh( regular_user3 )
- if not regular_user3.active_histories:
- raise AssertionError( 'HistoryDatasetAssociations for regular_user3 were incorrectly deleted when the user was marked deleted' )
- def test_040_undelete_user( self ):
- """Testing undeleting a user account"""
- # Logged in as admin_user
- self.undelete_user( user_id=self.security.encode_id( regular_user3.id ), email=regular_user3.email )
- def test_045_create_role( self ):
- """Testing creating new role with 3 members ( and a new group named the same ), then renaming the role"""
- # Logged in as admin_user
- name = 'Role One'
- description = "This is Role Ones description"
- user_ids=[ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ]
- self.create_role( name=name,
- description=description,
- in_user_ids=user_ids,
- in_group_ids=[],
- create_group_for_role='yes',
- private_role=admin_user.email )
- # Get the role object for later tests
- global role_one
- role_one = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first()
- assert role_one is not None, 'Problem retrieving role named "Role One" from the database'
- # Make sure UserRoleAssociations are correct
- if len( role_one.users ) != len( user_ids ):
- raise AssertionError( '%d UserRoleAssociations were created for role id %d when it was created ( should have been %d )' \
- % ( len( role_one.users ), role_one.id, len( user_ids ) ) )
- # Each of the following users should now have 2 role associations, their private role and role_one
- for user in [ admin_user, regular_user1, regular_user3 ]:
- sa_session.refresh( user )
- if len( user.roles ) != 2:
- raise AssertionError( '%d UserRoleAssociations are associated with user %s ( should be 2 )' \
- % ( len( user.roles ), user.email ) )
- # Make sure the group was created
- self.home()
- self.visit_page( 'admin/groups' )
- self.check_page_for_string( name )
- global group_zero
- group_zero = sa_session.query( galaxy.model.Group ).filter( galaxy.model.Group.table.c.name==name ).first()
- # Rename the role
- rename = "Role One's been Renamed"
- new_description="This is Role One's Re-described"
- self.rename_role( self.security.encode_id( role_one.id ), name=rename, description=new_description )
- self.home()
- self.visit_page( 'admin/roles' )
- self.check_page_for_string( rename )
- self.check_page_for_string( new_description )
- # Reset the role back to the original name and description
- self.rename_role( self.security.encode_id( role_one.id ), name=name, description=description )
- def test_050_create_group( self ):
- """Testing creating new group with 3 members and 1 associated role, then renaming it"""
- # Logged in as admin_user
- name = "Group One's Name"
- user_ids=[ str( admin_user.id ), str( regular_user1.id ), str( regular_user3.id ) ]
- role_ids=[ str( role_one.id ) ]
- self.create_group( name=name, in_user_ids=user_ids, in_role_ids=role_ids )
- # Get the group object for later tests
- global group_one
- group_one = sa_session.query( galaxy.model.Group ).filter( galaxy.model.Group.table.c.name==name ).first()
- assert group_one is not None, 'Problem retrieving group named "Group One" from the database'
- # Make sure UserGroupAssociations are correct
- if len( group_one.users ) != len( user_ids ):
- raise AssertionError( '%d UserGroupAssociations were created for group id %d when it was created ( should have been %d )' \
- % ( len( group_one.users ), group_one.id, len( user_ids ) ) )
- # Each user should now have 1 group association, group_one
- for user in [ admin_user, regular_user1, regular_user3 ]:
- sa_session.refresh( user )
- if len( user.groups ) != 1:
- raise AssertionError( '%d UserGroupAssociations are associated with user %s ( should be 1 )' % ( len( user.groups ), user.email ) )
- # Make sure GroupRoleAssociations are correct
- if len( group_one.roles ) != len( role_ids ):
- raise AssertionError( '%d GroupRoleAssociations were created for group id %d when it was created ( should have been %d )' \
- % ( len( group_one.roles ), group_one.id, len( role_ids ) ) )
- # Rename the group
- rename = "Group One's been Renamed"
- self.rename_group( self.security.encode_id( group_one.id ), name=rename, )
- self.home()
- self.visit_page( 'admin/groups' )
- self.check_page_for_string( rename )
- # Reset the group back to the original name
- self.rename_group( self.security.encode_id( group_one.id ), name=name )
- def test_055_add_members_and_role_to_group( self ):
- """Testing editing user membership and role associations of an existing group"""
- # Logged in as admin_user
- name = 'Group Two'
- self.create_group( name=name, in_user_ids=[], in_role_ids=[] )
- # Get the group object for later tests
- global group_two
- group_two = sa_session.query( galaxy.model.Group ).filter( galaxy.model.Group.table.c.name==name ).first()
- assert group_two is not None, 'Problem retrieving group named "Group Two" from the database'
- # group_two should have no associations
- if group_two.users:
- raise AssertionError( '%d UserGroupAssociations were created for group id %d when it was created ( should have been 0 )' \
- % ( len( group_two.users ), group_two.id ) )
- if group_two.roles:
- raise AssertionError( '%d GroupRoleAssociations were created for group id %d when it was created ( should have been 0 )' \
- % ( len( group_two.roles ), group_two.id ) )
- user_ids = [ str( regular_user1.id ) ]
- role_ids = [ str( role_one.id ) ]
- self.associate_users_and_roles_with_group( self.security.encode_id( group_two.id ),
- group_two.name,
- user_ids=user_ids,
- role_ids=role_ids )
- def test_060_create_role_with_user_and_group_associations( self ):
- """Testing creating a role with user and group associations"""
- # Logged in as admin_user
- # NOTE: To get this to work with twill, all select lists on the ~/admin/role page must contain at least
- # 1 option value or twill throws an exception, which is: ParseError: OPTION outside of SELECT
- # Due to this bug in twill, we create the role, we bypass the page and visit the URL in the
- # associate_users_and_groups_with_role() method.
- name = 'Role Two'
- description = 'This is Role Two'
- user_ids=[ str( admin_user.id ) ]
- group_ids=[ str( group_two.id ) ]
- private_role=admin_user.email
- # Create the role
- self.create_role( name=name,
- description=description,
- in_user_ids=user_ids,
- in_group_ids=group_ids,
- private_role=private_role )
- # Get the role object for later tests
- global role_two
- role_two = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first()
- assert role_two is not None, 'Problem retrieving role named "Role Two" from the database'
- # Make sure UserRoleAssociations are correct
- if len( role_two.users ) != len( user_ids ):
- raise AssertionError( '%d UserRoleAssociations were created for role id %d when it was created with %d members' \
- % ( len( role_two.users ), role_two.id, len( user_ids ) ) )
- # admin_user should now have 3 role associations, private role, role_one, role_two
- sa_session.refresh( admin_user )
- if len( admin_user.roles ) != 3:
- raise AssertionError( '%d UserRoleAssociations are associated with user %s ( should be 3 )' % ( len( admin_user.roles ), admin_user.email ) )
- # Make sure GroupRoleAssociations are correct
- sa_session.refresh( role_two )
- if len( role_two.groups ) != len( group_ids ):
- raise AssertionError( '%d GroupRoleAssociations were created for role id %d when it was created ( should have been %d )' \
- % ( len( role_two.groups ), role_two.id, len( group_ids ) ) )
- # group_two should now be associated with 2 roles: role_one, role_two
- sa_session.refresh( group_two )
- if len( group_two.roles ) != 2:
- raise AssertionError( '%d GroupRoleAssociations are associated with group id %d ( should be 2 )' % ( len( group_two.roles ), group_two.id ) )
- def test_065_change_user_role_associations( self ):
- """Testing changing roles associated with a user"""
- # Logged in as admin_user
- # Create a new role with no associations
- name = 'Role Three'
- description = 'This is Role Three'
- user_ids=[]
- group_ids=[]
- private_role=admin_user.email
- self.create_role( name=name,
- description=description,
- in_user_ids=user_ids,
- in_group_ids=group_ids,
- private_role=private_role )
- # Get the role object for later tests
- global role_three
- role_three = sa_session.query( galaxy.model.Role ).filter( galaxy.model.Role.table.c.name==name ).first()
- assert role_three is not None, 'Problem retrieving role named "Role Three" from the database'
- # Associate the role with a user
- sa_session.refresh( admin_user )
- role_ids = []
- for ura in admin_user.non_private_roles:
- role_ids.append( str( ura.role_id ) )
- role_ids.append( str( role_three.id ) )
- group_ids = []
- for uga in admin_user.groups:
- group_ids.append( str( uga.group_id ) )
- check_str = "User '%s' has been updated with %d associated roles and %d associated groups" % ( admin_user.email, len( role_ids ), len( group_ids ) )
- self.associate_roles_and_groups_with_user( self.security.encode_id( admin_user.id ),
- str( admin_user.email ),
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/e39c9a2a0b4c
changeset: 3527:e39c9a2a0b4c
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Fri Mar 12 14:27:04 2010 -0500
description:
UI Improvements:
-Make it possible to show messages in frames.
-Improve import interactions by showing messages in frames and providing useful links.
-Add action icons to display framework.
diffstat:
lib/galaxy/web/controllers/dataset.py | 16 +++++++++---
lib/galaxy/web/controllers/history.py | 35 ++++++++++++++++++---------
lib/galaxy/web/controllers/workflow.py | 22 +++++++++++++----
lib/galaxy/web/framework/__init__.py | 16 ++++++------
templates/dataset/display.mako | 10 ++++---
templates/display_base.mako | 7 +++--
templates/display_common.mako | 10 ++++++++
templates/grid_base.mako | 13 +--------
templates/grid_base_async.mako | 3 +-
templates/history/display.mako | 11 +--------
templates/message.mako | 36 +++++++++++++++++++++++++++-
templates/page/select_items_grid_async.mako | 3 +-
templates/workflow/display.mako | 6 +----
13 files changed, 122 insertions(+), 66 deletions(-)
diffs (411 lines):
diff -r f8c305ba23cb -r e39c9a2a0b4c lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Fri Mar 12 12:43:31 2010 -0500
+++ b/lib/galaxy/web/controllers/dataset.py Fri Mar 12 14:27:04 2010 -0500
@@ -418,17 +418,25 @@
return self.stored_list_grid( trans, status=status, message=message, **kwargs )
@web.expose
- def imp( self, trans, id=None, **kwd ):
+ def imp( self, trans, dataset_id=None, **kwd ):
""" Import another user's dataset via a shared URL; dataset is added to user's current history. """
msg = ""
+ # Set referer message.
+ referer = trans.request.referer
+ if referer is not "":
+ referer_message = "<a href='%s'>return to the previous page</a>" % referer
+ else:
+ referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
+
# Error checking.
- if not id:
- return trans.show_error_message( "You must specify an ID for a dataset to import." )
+ if not dataset_id:
+ return trans.show_error_message( "You must specify a dataset to import. You can %s." % referer_message, use_panels=True )
# Do import.
cur_history = trans.get_history( create=True )
- status, message = self._copy_datasets( trans, [ id ], [ cur_history ] )
+ status, message = self._copy_datasets( trans, [ dataset_id ], [ cur_history ] )
+ message = message + "<br>You can <a href='%s'>start using the dataset</a> or %s." % ( url_for('/'), referer_message )
return trans.show_message( message, type=status )
@web.expose
diff -r f8c305ba23cb -r e39c9a2a0b4c lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Fri Mar 12 12:43:31 2010 -0500
+++ b/lib/galaxy/web/controllers/history.py Fri Mar 12 14:27:04 2010 -0500
@@ -505,16 +505,27 @@
msg = ""
user = trans.get_user()
user_history = trans.get_history()
+ # Set referer message
+ if 'referer' in kwd:
+ referer = kwd['referer']
+ else:
+ referer = trans.request.referer
+ if referer is not "":
+ referer_message = "<a href='%s'>return to the previous page</a>" % referer
+ else:
+ referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
+
+ # Do import.
if not id:
- return trans.show_error_message( "You must specify a history you want to import." )
+ return trans.show_error_message( "You must specify a history you want to import.<br>You can %s." % referer_message, use_panels=True )
import_history = self.get_history( trans, id, check_ownership=False )
if not import_history:
- return trans.show_error_message( "The specified history does not exist.")
+ return trans.show_error_message( "The specified history does not exist.<br>You can %s." % referer_message, use_panels=True )
if not import_history.importable:
- error( "The owner of this history has disabled imports via this link." )
+ return trans.show_error_message( "The owner of this history has disabled imports via this link.<br>You can %s." % referer_message, use_panels=True )
if user:
if import_history.user_id == user.id:
- return trans.show_error_message( "You cannot import your own history." )
+ return trans.show_error_message( "You cannot import your own history.<br>You can %s." % referer_message, use_panels=True )
new_history = import_history.copy( target_user=user )
new_history.name = "imported: " + new_history.name
new_history.user_id = user.id
@@ -530,9 +541,9 @@
trans.sa_session.flush()
if not user_history.datasets:
trans.set_history( new_history )
- return trans.show_ok_message( """
- History "%s" has been imported. Click <a href="%s">here</a>
- to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
+ return trans.show_ok_message(
+ message="""History "%s" has been imported. <br>You can <a href="%s">start using this history</a> or %s."""
+ % ( new_history.name, web.url_for( '/' ), referer_message ), use_panels=True )
elif not user_history or not user_history.datasets or confirm:
new_history = import_history.copy()
new_history.name = "imported: " + new_history.name
@@ -548,13 +559,13 @@
trans.sa_session.add( new_history )
trans.sa_session.flush()
trans.set_history( new_history )
- return trans.show_ok_message( """
- History "%s" has been imported. Click <a href="%s">here</a>
- to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
+ return trans.show_ok_message(
+ message="""History "%s" has been imported. <br>You can <a href="%s">start using this history</a> or %s."""
+ % ( new_history.name, web.url_for( '/' ), referer_message ), use_panels=True )
return trans.show_warn_message( """
Warning! If you import this history, you will lose your current
- history. Click <a href="%s">here</a> to confirm.
- """ % web.url_for( id=id, confirm=True ) )
+ history. <br>You can <a href="%s">continue and import this history</a> or %s.
+ """ % ( web.url_for( id=id, confirm=True, referer=trans.request.referer ), referer_message ), use_panels=True )
@web.expose
def view( self, trans, id=None ):
diff -r f8c305ba23cb -r e39c9a2a0b4c lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Fri Mar 12 12:43:31 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Fri Mar 12 14:27:04 2010 -0500
@@ -278,18 +278,28 @@
@web.expose
@web.require_login( "use Galaxy workflows" )
def imp( self, trans, id, **kwargs ):
+ # Set referer message.
+ referer = trans.request.referer
+ if referer is not "":
+ referer_message = "<a href='%s'>return to the previous page</a>" % referer
+ else:
+ referer_message = "<a href='%s'>go to Galaxy's start page</a>" % url_for( '/' )
+
+ # Do import.
session = trans.sa_session
stored = self.get_stored_workflow( trans, id, check_ownership=False )
if stored.importable == False:
- error( "The owner of this workflow has disabled imports via this link" )
+ return trans.show_error_message( "The owner of this workflow has disabled imports via this link.<br>You can %s" % referer_message, use_panels=True )
elif stored.user == trans.user:
- error( "You are already the owner of this workflow, can't import" )
+ return trans.show_error_message( "You can't import this workflow because you own it.<br>You can %s" % referer_message, use_panels=True )
elif stored.deleted:
- error( "This workflow has been deleted, can't import" )
+ return trans.show_error_message( "You can't import this workflow because it has been deleted.<br>You can %s" % referer_message, use_panels=True )
elif session.query( model.StoredWorkflowUserShareAssociation ) \
.filter_by( user=trans.user, stored_workflow=stored ).count() > 0:
- error( "This workflow is already shared with you" )
+ # TODO: this is only reasonable as long as import creates a sharing relation.
+ return trans.show_error_message( "You can't import this workflow because it is already shared with you.<br>You can %s" % referer_message, use_panels=True )
else:
+ # TODO: Shouldn't an import provide a copy of a workflow?
share = model.StoredWorkflowUserShareAssociation()
share.stored_workflow = stored
share.user = trans.user
@@ -297,7 +307,9 @@
session.add( share )
session.flush()
# Redirect to load galaxy frames.
- return trans.response.send_redirect( url_for( controller='workflow' ) )
+ return trans.show_ok_message(
+ message="""Workflow "%s" has been imported. <br>You can <a href="%s">start using this workflow</a> or %s."""
+ % ( stored.name, web.url_for( controller='workflow' ), referer_message ), use_panels=True )
@web.expose
@web.require_login( "use Galaxy workflows" )
diff -r f8c305ba23cb -r e39c9a2a0b4c lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Fri Mar 12 12:43:31 2010 -0500
+++ b/lib/galaxy/web/framework/__init__.py Fri Mar 12 14:27:04 2010 -0500
@@ -561,7 +561,7 @@
context.
"""
return self.template_context['message']
- def show_message( self, message, type='info', refresh_frames=[], cont=None ):
+ def show_message( self, message, type='info', refresh_frames=[], cont=None, use_panels=False ):
"""
Convenience method for displaying a simple page with a single message.
@@ -571,22 +571,22 @@
`refresh_frames`: names of frames in the interface that should be
refreshed when the message is displayed
"""
- return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont )
- def show_error_message( self, message, refresh_frames=[] ):
+ return self.fill_template( "message.mako", message_type=type, message=message, refresh_frames=refresh_frames, cont=cont, use_panels=use_panels )
+ def show_error_message( self, message, refresh_frames=[], use_panels=False ):
"""
Convenience method for displaying an error message. See `show_message`.
"""
- return self.show_message( message, 'error', refresh_frames )
- def show_ok_message( self, message, refresh_frames=[] ):
+ return self.show_message( message, 'error', refresh_frames, use_panels=use_panels )
+ def show_ok_message( self, message, refresh_frames=[], use_panels=False ):
"""
Convenience method for displaying an ok message. See `show_message`.
"""
- return self.show_message( message, 'done', refresh_frames )
- def show_warn_message( self, message, refresh_frames=[] ):
+ return self.show_message( message, 'done', refresh_frames, use_panels=use_panels )
+ def show_warn_message( self, message, refresh_frames=[], use_panels=False ):
"""
Convenience method for displaying an warn message. See `show_message`.
"""
- return self.show_message( message, 'warning', refresh_frames )
+ return self.show_message( message, 'warning', refresh_frames, use_panels=use_panels )
def show_form( self, form, header=None, template="form.mako" ):
"""
Convenience method for displaying a simple page with a single HTML
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/dataset/display.mako
--- a/templates/dataset/display.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/dataset/display.mako Fri Mar 12 14:27:04 2010 -0500
@@ -23,7 +23,8 @@
<%def name="render_item_links( data )">
## Provide links to save data and TODO: import dataset.
- <a href="${h.url_for( controller='dataset', action='display', dataset_id=trans.security.encode_id( data.id ), to_ext=data.ext )}">save</a>
+ <a href="${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( data.id ), to_ext=data.ext )}" class="icon-button disk tooltip" title="Save dataset"></a>
+ <a href="${h.url_for( controller='/dataset', action='imp', dataset_id=trans.security.encode_id( data.id ) )}" class="icon-button import tooltip" title="Import dataset"></a>
</%def>
<%def name="render_item( data, data_to_render )">
@@ -49,11 +50,12 @@
<div class="unified-panel-body">
<div style="overflow: auto; height: 100%;">
<div class="page-body">
- <div style="padding: 0px 0px 5px 0px">
+ <div style="float: right">
${self.render_item_links( item )}
</div>
-
- ${self.render_item_header( item )}
+ <div>
+ ${self.render_item_header( item )}
+ </div>
${self.render_item( item, item_data )}
</div>
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/display_base.mako
--- a/templates/display_base.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/display_base.mako Fri Mar 12 14:27:04 2010 -0500
@@ -156,11 +156,12 @@
<div class="unified-panel-body">
<div style="overflow: auto; height: 100%;">
<div class="page-body">
- <div style="padding: 0px 0px 5px 0px">
+ <div style="float: right">
${self.render_item_links( item )}
</div>
-
- ${self.render_item_header( item )}
+ <div>
+ ${self.render_item_header( item )}
+ </div>
${self.render_item( item, item_data )}
</div>
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/display_common.mako
--- a/templates/display_common.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/display_common.mako Fri Mar 12 14:27:04 2010 -0500
@@ -128,3 +128,13 @@
%endif
</%def>
+## Render message.
+<%def name="render_message( message, message_type )">
+ %if message:
+ <p>
+ <div class="${message_type}message transient-message">${util.restore_text( message )}</div>
+ <div style="clear: both"></div>
+ </p>
+ %endif
+</%def>
+
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/grid_base.mako
--- a/templates/grid_base.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/grid_base.mako Fri Mar 12 14:27:04 2010 -0500
@@ -9,6 +9,7 @@
return '/base.mako'
%>
<%inherit file="${inherit(context)}"/>
+<%namespace file="/display_common.mako" import="render_message" />
<%def name="init()">
<%
@@ -663,23 +664,13 @@
<tr>
<td width="75%">${self.render_grid_header( grid )}</td>
<td></td>
- <td width="25%" id="grid-message" valign="top">${self.render_grid_message( grid )}</td>
+ <td width="25%" id="grid-message" valign="top">${render_message( message, message_type )}</td>
</tr>
</table>
${self.render_grid_table( grid )}
</%def>
-## Render grid message.
-<%def name="render_grid_message( grid )">
- %if message:
- <p>
- <div class="${message_type}message transient-message">${util.restore_text( message )}</div>
- <div style="clear: both"></div>
- </p>
- %endif
-</%def>
-
## Render grid header.
<%def name="render_grid_header( grid, render_title=True)">
<div class="grid-header">
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/grid_base_async.mako
--- a/templates/grid_base_async.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/grid_base_async.mako Fri Mar 12 14:27:04 2010 -0500
@@ -1,4 +1,5 @@
<%namespace file="./grid_base.mako" import="*" />
+<%namespace file="/display_common.mako" import="render_message" />
<%
# Set flag to indicate whether grid has operations that operate on multiple items.
@@ -12,4 +13,4 @@
*****
${num_pages}
*****
-${render_grid_message( grid )}
\ No newline at end of file
+${render_message( grid )}
\ No newline at end of file
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/history/display.mako
--- a/templates/history/display.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/history/display.mako Fri Mar 12 14:27:04 2010 -0500
@@ -236,16 +236,7 @@
</%def>
<%def name="render_item_links( history )">
- %if history.user != trans.get_user():
- <a href="${h.url_for( controller='/history', action='imp', id=trans.security.encode_id(history.id) )}">import and start using history</a>
- %else:
- ## TODO: add tooltip to indicate why this link is disabled.
- import and start using history
- %endif
- ##<a href="${self.get_history_link( history )}">${_('refresh')}</a>
- %if show_deleted:
- | <a href="${h.url_for('history', show_deleted=False)}">${_('hide deleted')}</a>
- %endif
+ <a href="${h.url_for( controller='/history', action='imp', id=trans.security.encode_id(history.id) )}" class="icon-button import tooltip" title="Import history"></a>
</%def>
<%def name="render_item( history, datasets )">
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/message.mako
--- a/templates/message.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/message.mako Fri Mar 12 14:27:04 2010 -0500
@@ -1,5 +1,21 @@
+<%!
+ def inherit(context):
+ if context.get('use_panels'):
+ return '/base_panels.mako'
+ else:
+ return '/base.mako'
+%>
+<%inherit file="${inherit(context)}"/>
<% _=n_ %>
-<%inherit file="/base.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view=active_view
+ self.message_box_visible=False
+%>
+</%def>
<%def name="javascripts()">
${parent.javascripts()}
@@ -45,7 +61,23 @@
</script>
</%def>
-<div class="${message_type}messagelarge">${_(message)}</div>
+##
+## Override methods from base.mako and base_panels.mako
+##
+
+<%def name="center_panel()">
+ ${render_large_message( message, message_type )}
+</%def>
+
+## Render the grid's basic elements. Each of these elements can be subclassed.
+<%def name="body()">
+ ${render_large_message( message, message_type )}
+</%def>
+
+## Render large message.
+<%def name="render_large_message( message, message_type )">
+ <div class="${message_type}messagelarge" style="margin: 1em">${_(message)}</div>
+</%def>
## Render a message
<%def name="render_msg( msg, messagetype='done' )">
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/page/select_items_grid_async.mako
--- a/templates/page/select_items_grid_async.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/page/select_items_grid_async.mako Fri Mar 12 14:27:04 2010 -0500
@@ -1,8 +1,9 @@
<%namespace file="../grid_base.mako" import="*" />
+<%namespace file="/display_common.mako" import="render_message" />
## Always show item checkboxes so that users can select histories.
${render_grid_table_body_contents( grid, show_item_checkboxes=True )}
*****
${num_pages}
*****
-${render_grid_message( grid )}
\ No newline at end of file
+${render_message( message, message_type )}
\ No newline at end of file
diff -r f8c305ba23cb -r e39c9a2a0b4c templates/workflow/display.mako
--- a/templates/workflow/display.mako Fri Mar 12 12:43:31 2010 -0500
+++ b/templates/workflow/display.mako Fri Mar 12 14:27:04 2010 -0500
@@ -77,11 +77,7 @@
<%def name="render_item_links( workflow )">
- %if workflow.user != trans.get_user():
- <a href="${h.url_for( controller='/workflow', action='imp', id=trans.security.encode_id(workflow.id) )}">import and start using workflow</a>
- %else:
- import and start using workflow
- %endif
+ <a href="${h.url_for( controller='/workflow', action='imp', id=trans.security.encode_id(workflow.id) )}" class="icon-button import tooltip" title="Import workflow"></a>
</%def>
<%def name="render_item( workflow, steps )">
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/f8c305ba23cb
changeset: 3526:f8c305ba23cb
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Fri Mar 12 12:43:31 2010 -0500
description:
When preparing Display Applications make manual click refresh link a non-javascript action.
diffstat:
templates/dataset/display_application/display.mako | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (11 lines):
diff -r 90fa86a7b4e3 -r f8c305ba23cb templates/dataset/display_application/display.mako
--- a/templates/dataset/display_application/display.mako Fri Mar 12 12:17:36 2010 -0500
+++ b/templates/dataset/display_application/display.mako Fri Mar 12 12:43:31 2010 -0500
@@ -7,6 +7,6 @@
%if refresh:
<%def name="metas()"><meta http-equiv="refresh" content="10" /></%def>
<p>
-This page will <a href="javascript:location.reload(true);">refresh</a> after 10 seconds.
+This page will <a href="${trans.request.url}">refresh</a> after 10 seconds.
</p>
%endif
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/90fa86a7b4e3
changeset: 3525:90fa86a7b4e3
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Fri Mar 12 12:17:36 2010 -0500
description:
Tweaks for flow control in Display applications:
Display Applications now use trans.response.send_redirect instead of javascript when redirecting users to prepared display applications.
Display Applications now use a <meta> refresh instead of a javascript based refresh when notifying users that the display application is being prepared.
diffstat:
lib/galaxy/web/controllers/dataset.py | 3 ++-
templates/dataset/display_application/display.mako | 9 ++-------
templates/dataset/display_application/launch_display.mako | 15 ---------------
3 files changed, 4 insertions(+), 23 deletions(-)
diffs (55 lines):
diff -r 5f967426f33f -r 90fa86a7b4e3 lib/galaxy/web/controllers/dataset.py
--- a/lib/galaxy/web/controllers/dataset.py Fri Mar 12 12:03:25 2010 -0500
+++ b/lib/galaxy/web/controllers/dataset.py Fri Mar 12 12:17:36 2010 -0500
@@ -557,7 +557,8 @@
trans.response.headers[ 'Content-Length' ] = content_length
return rval
elif app_action == None:
- return trans.fill_template_mako( "dataset/display_application/launch_display.mako", display_link = display_link )
+ #redirect user to url generated by display link
+ return trans.response.send_redirect( display_link.display_url() )
else:
msg.append( ( 'Invalid action provided: %s' % app_action, 'error' ) )
else:
diff -r 5f967426f33f -r 90fa86a7b4e3 templates/dataset/display_application/display.mako
--- a/templates/dataset/display_application/display.mako Fri Mar 12 12:03:25 2010 -0500
+++ b/templates/dataset/display_application/display.mako Fri Mar 12 12:17:36 2010 -0500
@@ -1,17 +1,12 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
<%def name="title()">Display Application: ${display_link.link.display_application.name} ${display_link.link.name}</%def>
-<% refresh_rate = 10 %>
-%if refresh:
-<script type="text/javascript">
- setTimeout( "location.reload(true);", ${ refresh_rate * 1000 } );
-</script>
-%endif
%for message, message_type in msg:
${render_msg( message, message_type )}
%endfor
%if refresh:
+<%def name="metas()"><meta http-equiv="refresh" content="10" /></%def>
<p>
-This page will <a href="javascript:location.reload(true);">refresh</a> after ${refresh_rate} seconds.
+This page will <a href="javascript:location.reload(true);">refresh</a> after 10 seconds.
</p>
%endif
diff -r 5f967426f33f -r 90fa86a7b4e3 templates/dataset/display_application/launch_display.mako
--- a/templates/dataset/display_application/launch_display.mako Fri Mar 12 12:03:25 2010 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-<%inherit file="/base.mako"/>
-<%def name="title()">Launching Display Application: ${display_link.link.display_application.name} ${display_link.link.name}</%def>
-
-<script type="text/javascript">
- location.href = '${display_link.display_url()}';
-</script>
-<p>
-All data has been prepared for the external display application: ${display_link.link.display_application.name} ${display_link.link.name}.
-</p>
-<p>
-You are now being automatically forwarded to the external application.
-</p>
-<p>
-Click <a href="${display_link.display_url()}">here</a> if this redirect has failed.
-</p>
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/5f967426f33f
changeset: 3524:5f967426f33f
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Fri Mar 12 12:03:25 2010 -0500
description:
Add 'metas()' %def to base.mako, to allow subclassing templates to declare additional <meta/> tags.
diffstat:
templates/base.mako | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diffs (17 lines):
diff -r c3eccab29814 -r 5f967426f33f templates/base.mako
--- a/templates/base.mako Fri Mar 12 09:37:22 2010 -0500
+++ b/templates/base.mako Fri Mar 12 12:03:25 2010 -0500
@@ -5,6 +5,7 @@
<head>
<title>${self.title()}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+${self.metas()}
${self.stylesheets()}
${self.javascripts()}
</head>
@@ -30,3 +31,5 @@
${h.js( "jquery", "galaxy.base" )}
</%def>
+## Additional metas can be defined by templates inheriting from this one.
+<%def name="metas()"></%def>
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/c3eccab29814
changeset: 3523:c3eccab29814
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Fri Mar 12 09:37:22 2010 -0500
description:
Make visualizations sharable, publishable, taggable, and annotate-able. Plumbing code is in place, but UI code needs work; in particular, viewing a shared/published visualization is empty and annotations are available only via edit attributes.
Some code tidying: refactoring, removing unused code.
diffstat:
lib/galaxy/model/__init__.py | 16 +-
lib/galaxy/model/mapping.py | 73 +-
lib/galaxy/model/migrate/versions/0043_visualization_sharing_tagging_annotating.py | 220 ++++++
lib/galaxy/tags/tag_handler.py | 1 +
lib/galaxy/web/base/controller.py | 39 +-
lib/galaxy/web/buildapp.py | 1 +
lib/galaxy/web/controllers/history.py | 56 +-
lib/galaxy/web/controllers/page.py | 21 +-
lib/galaxy/web/controllers/tracks.py | 4 +-
lib/galaxy/web/controllers/visualization.py | 322 +++++++++-
lib/galaxy/web/controllers/workflow.py | 6 +-
templates/base_panels.mako | 2 +-
templates/display_common.mako | 7 +-
templates/page/create.mako | 3 +-
templates/panels.mako | 2 -
templates/visualization/create.mako | 14 +
templates/visualization/display.mako | 19 +
templates/visualization/list.mako | 52 +
templates/visualization/list_published.mako | 36 +
19 files changed, 773 insertions(+), 121 deletions(-)
diffs (1317 lines):
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/model/__init__.py Fri Mar 12 09:37:22 2010 -0500
@@ -1527,6 +1527,11 @@
self.title = None
self.config = None
+class VisualizationUserShareAssociation( object ):
+ def __init__( self ):
+ self.visualization = None
+ self.user = None
+
class Tag ( object ):
def __init__( self, id=None, type=None, parent_id=None, name=None ):
self.id = id
@@ -1558,16 +1563,16 @@
class PageTagAssociation ( ItemTagAssociation ):
pass
-
-class WorkflowTagAssociation ( ItemTagAssociation ):
- pass
-
+
class WorkflowStepTagAssociation ( ItemTagAssociation ):
pass
class StoredWorkflowTagAssociation ( ItemTagAssociation ):
pass
+class VisualizationTagAssociation ( ItemTagAssociation ):
+ pass
+
class HistoryAnnotationAssociation( object ):
pass
@@ -1583,6 +1588,9 @@
class PageAnnotationAssociation( object ):
pass
+class VisualizationAnnotationAssociation( object ):
+ pass
+
class UserPreference ( object ):
def __init__( self, name=None, value=None ):
self.name = name
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/model/mapping.py Fri Mar 12 09:37:22 2010 -0500
@@ -80,7 +80,7 @@
Column( "genome_build", TrimmedString( 40 ) ),
Column( "importable", Boolean, default=False ),
Column( "slug", TEXT, index=True ),
- Column( "published", Boolean, index=True ) )
+ Column( "published", Boolean, index=True, default=False ) )
HistoryUserShareAssociation.table = Table( "history_user_share_association", metadata,
Column( "id", Integer, primary_key=True ),
@@ -521,7 +521,7 @@
Column( "deleted", Boolean, default=False ),
Column( "importable", Boolean, default=False ),
Column( "slug", TEXT, index=True ),
- Column( "published", Boolean, index=True )
+ Column( "published", Boolean, index=True, default=False )
)
Workflow.table = Table( "workflow", metadata,
@@ -721,7 +721,11 @@
Column( "latest_revision_id", Integer,
ForeignKey( "visualization_revision.id", use_alter=True, name='visualization_latest_revision_id_fk' ), index=True ),
Column( "title", TEXT ),
- Column( "type", TEXT )
+ Column( "type", TEXT ),
+ Column( "deleted", Boolean, default=False, index=True ),
+ Column( "importable", Boolean, default=False, index=True ),
+ Column( "slug", TEXT, index=True ),
+ Column( "published", Boolean, default=False, index=True )
)
VisualizationRevision.table = Table( "visualization_revision", metadata,
@@ -733,6 +737,12 @@
Column( "config", JSONType )
)
+VisualizationUserShareAssociation.table = Table( "visualization_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
+
# Tagging tables.
Tag.table = Table( "tag", metadata,
@@ -768,16 +778,7 @@
Column( "user_tname", TrimmedString(255), index=True),
Column( "value", TrimmedString(255), index=True),
Column( "user_value", TrimmedString(255), index=True) )
-
-WorkflowTagAssociation.table = Table( "workflow_tag_association", metadata,
- Column( "id", Integer, primary_key=True ),
- Column( "workflow_id", Integer, ForeignKey( "workflow.id" ), index=True ),
- Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ),
- Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
- Column( "user_tname", Unicode(255), index=True),
- Column( "value", Unicode(255), index=True),
- Column( "user_value", Unicode(255), index=True) )
-
+
StoredWorkflowTagAssociation.table = Table( "stored_workflow_tag_association", metadata,
Column( "id", Integer, primary_key=True ),
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True ),
@@ -805,6 +806,15 @@
Column( "value", Unicode(255), index=True),
Column( "user_value", Unicode(255), index=True) )
+VisualizationTagAssociation.table = Table( "visualization_tag_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "user_tname", TrimmedString(255), index=True),
+ Column( "value", TrimmedString(255), index=True),
+ Column( "user_value", TrimmedString(255), index=True) )
+
# Annotation tables.
HistoryAnnotationAssociation.table = Table( "history_annotation_association", metadata,
@@ -836,6 +846,12 @@
Column( "page_id", Integer, ForeignKey( "page.id" ), index=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "annotation", TEXT, index=True) )
+
+VisualizationAnnotationAssociation.table = Table( "visualization_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=True) )
# User tables.
@@ -1271,8 +1287,7 @@
properties=dict( steps=relation( WorkflowStep, backref='workflow',
order_by=asc(WorkflowStep.table.c.order_index),
cascade="all, delete-orphan",
- lazy=False ),
- tags=relation(WorkflowTagAssociation, order_by=WorkflowTagAssociation.table.c.id, backref="workflows")
+ lazy=False )
) )
assign_mapper( context, WorkflowStep, WorkflowStep.table,
@@ -1359,8 +1374,20 @@
primaryjoin=( Visualization.table.c.id == VisualizationRevision.table.c.visualization_id ) ),
latest_revision=relation( VisualizationRevision, post_update=True,
primaryjoin=( Visualization.table.c.latest_revision_id == VisualizationRevision.table.c.id ),
- lazy=False )
+ lazy=False ),
+ tags=relation( VisualizationTagAssociation, order_by=VisualizationTagAssociation.table.c.id, backref="visualizations" ),
+ annotations=relation( VisualizationAnnotationAssociation, order_by=VisualizationAnnotationAssociation.table.c.id, backref="visualizations" )
) )
+
+# Set up proxy so that
+# Visualization.users_shared_with_dot_users
+# returns a list of User objects for users that a visualization is shared with.
+Visualization.users_shared_with_dot_users = association_proxy( 'users_shared_with', 'user' )
+
+assign_mapper( context, VisualizationUserShareAssociation, VisualizationUserShareAssociation.table,
+ properties=dict( user=relation( User, backref='visualizations_shared_by_others' ),
+ visualization=relation( Visualization, backref='users_shared_with' )
+ ) )
assign_mapper( context, Tag, Tag.table,
properties=dict( children=relation(Tag, backref=backref( 'parent', remote_side=[Tag.table.c.id] ) )
@@ -1381,19 +1408,19 @@
assign_mapper( context, PageTagAssociation, PageTagAssociation.table,
properties=dict( tag=relation(Tag, backref="tagged_pages"), user=relation( User ) )
)
-
-assign_mapper( context, WorkflowTagAssociation, WorkflowTagAssociation.table,
- properties=dict( tag=relation(Tag, backref="tagged_workflows"), user=relation( User ) )
- )
assign_mapper( context, StoredWorkflowTagAssociation, StoredWorkflowTagAssociation.table,
- properties=dict( tag=relation(Tag, backref="tagged_stored_workflows"), user=relation( User ) )
+ properties=dict( tag=relation(Tag, backref="tagged_workflows"), user=relation( User ) )
)
assign_mapper( context, WorkflowStepTagAssociation, WorkflowStepTagAssociation.table,
properties=dict( tag=relation(Tag, backref="tagged_workflow_steps"), user=relation( User ) )
)
+assign_mapper( context, VisualizationTagAssociation, VisualizationTagAssociation.table,
+ properties=dict( tag=relation(Tag, backref="tagged_visualizations"), user=relation( User ) )
+ )
+
assign_mapper( context, HistoryAnnotationAssociation, HistoryAnnotationAssociation.table,
properties=dict( history=relation( History ), user=relation( User ) )
)
@@ -1414,6 +1441,10 @@
properties=dict( page=relation( Page ), user=relation( User ) )
)
+assign_mapper( context, VisualizationAnnotationAssociation, VisualizationAnnotationAssociation.table,
+ properties=dict( visualization=relation( Visualization ), user=relation( User ) )
+ )
+
assign_mapper( context, UserPreference, UserPreference.table,
properties = {}
)
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/model/migrate/versions/0043_visualization_sharing_tagging_annotating.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0043_visualization_sharing_tagging_annotating.py Fri Mar 12 09:37:22 2010 -0500
@@ -0,0 +1,220 @@
+"""
+Migration script to create tables and columns for sharing visualizations.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+# Sharing visualizations.
+
+VisualizationUserShareAssociation_table = Table( "visualization_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
+
+# Tagging visualizations.
+
+VisualizationTagAssociation_table = Table( "visualization_tag_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "tag_id", Integer, ForeignKey( "tag.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "user_tname", Unicode(255), index=True),
+ Column( "value", Unicode(255), index=True),
+ Column( "user_value", Unicode(255), index=True) )
+
+# Annotating visualizations.
+
+VisualizationAnnotationAssociation_table = Table( "visualization_annotation_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "visualization_id", Integer, ForeignKey( "visualization.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
+ Column( "annotation", TEXT, index=False ) )
+
+Visualiation_table = Table( "visualization", metadata, autoload=True )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create visualization_user_share_association table.
+ try:
+ VisualizationUserShareAssociation_table.create()
+ except Exception, e:
+ print "Creating visualization_user_share_association table failed: %s" % str( e )
+ log.debug( "Creating visualization_user_share_association table failed: %s" % str( e ) )
+
+ # Get default boolean value 'false' so that columns can be initialized.
+ if migrate_engine.name == 'mysql':
+ default_false = "0"
+ elif migrate_engine.name == 'sqlite':
+ default_false = "'false'"
+ elif migrate_engine.name == 'postgres':
+ default_false = "false"
+
+ # Add columns & create indices for supporting sharing to visualization table.
+ deleted_column = Column( "deleted", Boolean, default=False, index=True )
+ importable_column = Column( "importable", Boolean, default=False, index=True )
+ slug_column = Column( "slug", TEXT, index=True )
+ published_column = Column( "published", Boolean, index=True )
+
+ try:
+ # Add column.
+ deleted_column.create( Visualiation_table )
+ assert deleted_column is Visualiation_table.c.deleted
+
+ # Fill column with default value.
+ cmd = "UPDATE visualization SET deleted = %s" % default_false
+ db_session.execute( cmd )
+ except Exception, e:
+ print "Adding deleted column to visualization table failed: %s" % str( e )
+ log.debug( "Adding deleted column to visualization table failed: %s" % str( e ) )
+
+ try:
+ i = Index( "ix_visualization_deleted", Visualiation_table.c.deleted )
+ i.create()
+ except Exception, e:
+ print "Adding index 'ix_visualization_deleted' failed: %s" % str( e )
+ log.debug( "Adding index 'ix_visualization_deleted' failed: %s" % str( e ) )
+
+ try:
+ # Add column.
+ importable_column.create( Visualiation_table )
+ assert importable_column is Visualiation_table.c.importable
+
+ # Fill column with default value.
+ cmd = "UPDATE visualization SET importable = %s" % default_false
+ db_session.execute( cmd )
+ except Exception, e:
+ print "Adding importable column to visualization table failed: %s" % str( e )
+ log.debug( "Adding importable column to visualization table failed: %s" % str( e ) )
+
+ i = Index( "ix_visualization_importable", Visualiation_table.c.importable )
+ try:
+ i.create()
+ except Exception, e:
+ print "Adding index 'ix_visualization_importable' failed: %s" % str( e )
+ log.debug( "Adding index 'ix_visualization_importable' failed: %s" % str( e ) )
+
+ try:
+ slug_column.create( Visualiation_table )
+ assert slug_column is Visualiation_table.c.slug
+ except Exception, e:
+ print "Adding slug column to visualization table failed: %s" % str( e )
+ log.debug( "Adding slug column to visualization table failed: %s" % str( e ) )
+
+ try:
+ if migrate_engine.name == 'mysql':
+ # Have to create index manually.
+ cmd = "CREATE INDEX ix_visualization_slug ON visualization ( slug ( 100 ) )"
+ db_session.execute( cmd )
+ else:
+ i = Index( "ix_visualization_slug", Visualiation_table.c.slug )
+ i.create()
+ except Exception, e:
+ print "Adding index 'ix_visualization_slug' failed: %s" % str( e )
+ log.debug( "Adding index 'ix_visualization_slug' failed: %s" % str( e ) )
+
+ try:
+ # Add column.
+ published_column.create( Visualiation_table )
+ assert published_column is Visualiation_table.c.published
+
+ # Fill column with default value.
+ cmd = "UPDATE visualization SET published = %s" % default_false
+ db_session.execute( cmd )
+ except Exception, e:
+ print "Adding published column to visualization table failed: %s" % str( e )
+ log.debug( "Adding published column to visualization table failed: %s" % str( e ) )
+
+ i = Index( "ix_visualization_published", Visualiation_table.c.published )
+ try:
+ i.create()
+ except Exception, e:
+ print "Adding index 'ix_visualization_published' failed: %s" % str( e )
+ log.debug( "Adding index 'ix_visualization_published' failed: %s" % str( e ) )
+
+ # Create visualization_tag_association table.
+ try:
+ VisualizationTagAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating visualization_tag_association table failed: %s" % str( e ) )
+
+ # Create visualization_annotation_association table.
+ try:
+ VisualizationAnnotationAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating visualization_annotation_association table failed: %s" % str( e ) )
+
+ # Need to create index for visualization annotation manually to deal with errors.
+ try:
+ if migrate_engine.name == 'mysql':
+ # Have to create index manually.
+ cmd = "CREATE INDEX ix_visualization_annotation_association_annotation ON visualization_annotation_association ( annotation ( 100 ) )"
+ db_session.execute( cmd )
+ else:
+ i = Index( "ix_visualization_annotation_association_annotation", VisualizationAnnotationAssociation_table.c.annotation )
+ i.create()
+ except Exception, e:
+ print "Adding index 'ix_visualization_annotation_association_annotation' failed: %s" % str( e )
+ log.debug( "Adding index 'ix_visualization_annotation_association_annotation' failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop visualization_user_share_association table.
+ try:
+ VisualizationUserShareAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping visualization_user_share_association table failed: %s" % str( e ) )
+
+ # Drop columns for supporting sharing from visualization table.
+ try:
+ Visualiation_table.c.deleted.drop()
+ except Exception, e:
+ print "Dropping deleted column from visualization table failed: %s" % str( e )
+ log.debug( "Dropping deleted column from visualization table failed: %s" % str( e ) )
+
+ try:
+ Visualiation_table.c.importable.drop()
+ except Exception, e:
+ print "Dropping importable column from visualization table failed: %s" % str( e )
+ log.debug( "Dropping importable column from visualization table failed: %s" % str( e ) )
+
+ try:
+ Visualiation_table.c.slug.drop()
+ except Exception, e:
+ print "Dropping slug column from visualization table failed: %s" % str( e )
+ log.debug( "Dropping slug column from visualization table failed: %s" % str( e ) )
+
+ try:
+ Visualiation_table.c.published.drop()
+ except Exception, e:
+ print "Dropping published column from visualization table failed: %s" % str( e )
+ log.debug( "Dropping published column from visualization table failed: %s" % str( e ) )
+
+ # Drop visualization_tag_association table.
+ try:
+ VisualizationTagAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping visualization_tag_association table failed: %s" % str( e ) )
+
+ # Drop visualization_annotation_association table.
+ try:
+ VisualizationAnnotationAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping visualization_annotation_association table failed: %s" % str( e ) )
\ No newline at end of file
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/tags/tag_handler.py
--- a/lib/galaxy/tags/tag_handler.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/tags/tag_handler.py Fri Mar 12 09:37:22 2010 -0500
@@ -34,6 +34,7 @@
ItemTagAssocInfo( model.HistoryDatasetAssociation, model.HistoryDatasetAssociationTagAssociation, model.HistoryDatasetAssociationTagAssociation.table.c.history_dataset_association_id )
item_tag_assoc_info["Page"] = ItemTagAssocInfo( model.Page, model.PageTagAssociation, model.PageTagAssociation.table.c.page_id )
item_tag_assoc_info["StoredWorkflow"] = ItemTagAssocInfo( model.StoredWorkflow, model.StoredWorkflowTagAssociation, model.StoredWorkflowTagAssociation.table.c.stored_workflow_id )
+ item_tag_assoc_info["Visualization"] = ItemTagAssocInfo( model.Visualization, model.VisualizationTagAssociation, model.VisualizationTagAssociation.table.c.visualization_id )
def get_tag_assoc_class(self, item_class):
""" Returns tag association class for item class. """
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/base/controller.py Fri Mar 12 09:37:22 2010 -0500
@@ -16,6 +16,9 @@
# States for passing messages
SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
+
+# RE that tests for valid slug.
+VALID_SLUG_RE = re.compile( "^[a-z0-9\-]+$" )
class BaseController( object ):
"""
@@ -40,6 +43,8 @@
item_class = model.Page
elif class_name == 'StoredWorkflow':
item_class = model.StoredWorkflow
+ elif class_name == 'Visualization':
+ item_class = model.Visualization
else:
item_class = None
return item_class
@@ -76,6 +81,8 @@
annotation_assoc = annotation_assoc.filter_by( workflow_step=item )
elif item.__class__ == model.Page:
annotation_assoc = annotation_assoc.filter_by( page=item )
+ elif item.__class__ == model.Visualization:
+ annotation_assoc = annotation_assoc.filter_by( visualization=item )
return annotation_assoc.first()
def add_item_annotation( self, trans, item, annotation ):
@@ -153,6 +160,19 @@
truncated = False
return truncated, dataset_data
+class UsesVisualization( SharableItemSecurity ):
+ """ Mixin for controllers that use Visualization objects. """
+
+ def get_visualization( self, trans, id, check_ownership=True, check_accessible=False ):
+ """ Get a Visualization from the database by id, verifying ownership. """
+ # Load workflow from database
+ id = trans.security.decode_id( id )
+ visualization = trans.sa_session.query( model.Visualization ).get( id )
+ if not visualization:
+ error( "Visualization not found" )
+ else:
+ return self.security_check( trans.get_user(), stored, check_ownership, check_accessible )
+
class UsesStoredWorkflow( SharableItemSecurity ):
""" Mixin for controllers that use StoredWorkflow objects. """
@@ -240,6 +260,12 @@
pass
@web.expose
+ @web.require_login( "share Galaxy items" )
+ def share( self, trans, id=None, email="", **kwd ):
+ """ Handle sharing an item with a particular user. """
+ pass
+
+ @web.expose
def display_by_username_and_slug( self, trans, username, slug ):
""" Display item by username and slug. """
pass
@@ -262,13 +288,18 @@
def _make_item_accessible( self, sa_session, item ):
""" Makes item accessible--viewable and importable--and sets item's slug. Does not flush/commit changes, however. Item must have name, user, importable, and slug attributes. """
item.importable = True
- self.set_item_slug( sa_session, item )
+ self.create_item_slug( sa_session, item )
- def set_item_slug( self, sa_session, item ):
- """ Set item slug. Slug is unique among user's importable items for item's class. Returns true if item's slug was set; false otherwise. """
+ def create_item_slug( self, sa_session, item ):
+ """ Create item slug. Slug is unique among user's importable items for item's class. Returns true if item's slug was set; false otherwise. """
if item.slug is None or item.slug == "":
+ # Item can have either a name or a title.
+ if hasattr( item, 'name' ):
+ item_name = item.name
+ elif hasattr( item, 'title' ):
+ item_name = item.title
# Replace whitespace with '-'
- slug_base = re.sub( "\s+", "-", item.name.lower() )
+ slug_base = re.sub( "\s+", "-", item_name.lower() )
# Remove all non-alphanumeric characters.
slug_base = re.sub( "[^a-zA-Z0-9\-]", "", slug_base )
# Remove trailing '-'.
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/buildapp.py
--- a/lib/galaxy/web/buildapp.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/buildapp.py Fri Mar 12 09:37:22 2010 -0500
@@ -79,6 +79,7 @@
webapp.add_route( '/u/:username/p/:slug', controller='page', action='display_by_username_and_slug' )
webapp.add_route( '/u/:username/h/:slug', controller='history', action='display_by_username_and_slug' )
webapp.add_route( '/u/:username/w/:slug', controller='workflow', action='display_by_username_and_slug' )
+ webapp.add_route( '/u/:username/v/:slug', controller='visualization', action='display_by_username_and_slug' )
webapp.finalize_config()
# Wrap the webapp in some useful middleware
if kwargs.get( 'middleware', True ):
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/controllers/history.py Fri Mar 12 09:37:22 2010 -0500
@@ -440,7 +440,7 @@
""" Returns history's name and link. """
history = self.get_history( trans, id, False )
- if self.set_item_slug( trans.sa_session, history ):
+ if self.create_item_slug( trans.sa_session, history ):
trans.sa_session.flush()
return_dict = { "name" : history.name, "link" : url_for( action="display_by_username_and_slug", username=history.user.username, slug=history.slug ) }
return return_dict
@@ -652,58 +652,6 @@
session.flush()
return trans.fill_template( "/sharing_base.mako", item=history )
-
- ## TODO: remove this method when history sharing has been verified to work correctly with new sharing() method.
- @web.expose
- @web.require_login( "share histories with other users" )
- def sharing_old( self, trans, histories=[], id=None, **kwd ):
- """Performs sharing of histories among users."""
- # histories looks like: [ historyX, historyY ]
- params = util.Params( kwd )
- msg = util.restore_text ( params.get( 'msg', '' ) )
- if id:
- ids = util.listify( id )
- if ids:
- histories = [ self.get_history( trans, history_id ) for history_id in ids ]
- for history in histories:
- trans.sa_session.add( history )
- if params.get( 'enable_import_via_link', False ):
- self._make_item_accessible( trans.sa_session, history )
- trans.sa_session.flush()
- elif params.get( 'disable_import_via_link', False ):
- history.importable = False
- trans.sa_session.flush()
- elif params.get( 'unshare_user', False ):
- user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( kwd[ 'unshare_user' ] ) )
- if not user:
- msg = 'History (%s) does not seem to be shared with user (%s)' % ( history.name, user.email )
- return trans.fill_template( 'history/sharing.mako', histories=histories, msg=msg, messagetype='error' )
- husas = trans.sa_session.query( trans.app.model.HistoryUserShareAssociation ).filter_by( user=user, history=history ).all()
- if husas:
- for husa in husas:
- trans.sa_session.delete( husa )
- trans.sa_session.flush()
- histories = []
- # Get all histories that have been shared with others
- husas = trans.sa_session.query( trans.app.model.HistoryUserShareAssociation ) \
- .join( "history" ) \
- .filter( and_( trans.app.model.History.user == trans.user,
- trans.app.model.History.deleted == False ) ) \
- .order_by( trans.app.model.History.table.c.name )
- for husa in husas:
- history = husa.history
- if history not in histories:
- histories.append( history )
- # Get all histories that are importable
- importables = trans.sa_session.query( trans.app.model.History ) \
- .filter_by( user=trans.user, importable=True, deleted=False ) \
- .order_by( trans.app.model.History.table.c.name )
- for importable in importables:
- if importable not in histories:
- histories.append( importable )
- # Sort the list of histories by history.name
- histories.sort( key=operator.attrgetter( 'name') )
- return trans.fill_template( 'history/sharing.mako', histories=histories, msg=msg, messagetype='done' )
@web.expose
@web.require_login( "share histories with other users" )
@@ -975,7 +923,7 @@
share.history = history
share.user = send_to_user
trans.sa_session.add( share )
- self.set_item_slug( trans.sa_session, history )
+ self.create_item_slug( trans.sa_session, history )
trans.sa_session.flush()
if history not in shared_histories:
shared_histories.append( history )
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/controllers/page.py
--- a/lib/galaxy/web/controllers/page.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/controllers/page.py Fri Mar 12 09:37:22 2010 -0500
@@ -4,10 +4,6 @@
from galaxy.util.odict import odict
from galaxy.util.json import from_json_string
-import re
-
-VALID_SLUG_RE = re.compile( "^[a-z0-9\-]+$" )
-
def format_bool( b ):
if b:
return "yes"
@@ -45,8 +41,8 @@
]
operations = [
grids.DisplayByUsernameAndSlugGridOperation( "View", allow_multiple=False ),
+ grids.GridOperation( "Edit content", allow_multiple=False, url_args=dict( action='edit_content') ),
grids.GridOperation( "Edit attributes", allow_multiple=False, url_args=dict( action='edit') ),
- grids.GridOperation( "Edit content", allow_multiple=False, url_args=dict( action='edit_content') ),
grids.GridOperation( "Share or Publish", allow_multiple=False, condition=( lambda item: not item.deleted ), async_compatible=False ),
grids.GridOperation( "Delete", confirm="Are you sure you want to delete this page?" ),
]
@@ -62,7 +58,7 @@
default_sort_key = "-update_time"
default_filter = dict( title="All", username="All" )
columns = [
- grids.PublicURLColumn( "Title", key="title", model_class=model.Page, filterable="advanced"),
+ grids.PublicURLColumn( "Title", key="title", model_class=model.Page, filterable="advanced" ),
grids.OwnerAnnotationColumn( "Annotation", key="annotation", model_class=model.Page, model_annotation_association_class=model.PageAnnotationAssociation, filterable="advanced" ),
grids.OwnerColumn( "Owner", key="username", model_class=model.User, filterable="advanced", sortable=False ),
grids.CommunityTagsColumn( "Community Tags", "tags", model.Page, model.PageTagAssociation, filterable="advanced", grid_name="PageAllPublishedGrid" ),
@@ -356,10 +352,10 @@
template="page/create.mako" )
@web.expose
- @web.require_login( "create pages" )
+ @web.require_login( "edit pages" )
def edit( self, trans, id, page_title="", page_slug="", page_annotation="" ):
"""
- Create a new page
+ Edit a page's attributes.
"""
encoded_id = id
id = trans.security.decode_id( id )
@@ -456,6 +452,7 @@
@web.expose
@web.require_login( "use Galaxy pages" )
def share( self, trans, id, email="" ):
+ """ Handle sharing with an individual user. """
msg = mtype = None
page = trans.sa_session.query( model.Page ).get( trans.security.decode_id( id ) )
if email:
@@ -468,18 +465,18 @@
msg = ( "User '%s' does not exist" % email )
elif other == trans.get_user():
mtype = "error"
- msg = ( "You cannot share a workflow with yourself" )
+ msg = ( "You cannot share a page with yourself" )
elif trans.sa_session.query( model.PageUserShareAssociation ) \
.filter_by( user=other, page=page ).count() > 0:
mtype = "error"
- msg = ( "Workflow already shared with '%s'" % email )
+ msg = ( "Page already shared with '%s'" % email )
else:
share = model.PageUserShareAssociation()
share.page = page
share.user = other
session = trans.sa_session
session.add( share )
- self.set_item_slug( session, page )
+ self.create_item_slug( session, page )
session.flush()
trans.set_message( "Page '%s' shared with user '%s'" % ( page.title, other.email ) )
return trans.response.send_redirect( url_for( controller='page', action='sharing', id=id ) )
@@ -609,7 +606,7 @@
""" Returns page's name and link. """
page = self.get_page( trans, id )
- if self.set_item_slug( trans.sa_session, page ):
+ if self.create_item_slug( trans.sa_session, page ):
trans.sa_session.flush()
return_dict = { "name" : page.title, "link" : url_for( action="display_by_username_and_slug", username=page.user.username, slug=page.slug ) }
return return_dict
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/controllers/tracks.py Fri Mar 12 09:37:22 2010 -0500
@@ -262,7 +262,9 @@
@web.json
def save( self, trans, **kwargs ):
session = trans.sa_session
- vis_id = kwargs['vis_id'].strip('"')
+ vis_id = "undefined"
+ if 'vis_id' in kwargs:
+ vis_id = kwargs['vis_id'].strip('"')
dbkey = kwargs['dbkey']
if vis_id == "undefined": # new vis
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/controllers/visualization.py
--- a/lib/galaxy/web/controllers/visualization.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/controllers/visualization.py Fri Mar 12 09:37:22 2010 -0500
@@ -1,35 +1,325 @@
from galaxy.web.base.controller import *
-from galaxy.web.framework.helpers import time_ago, grids
+from galaxy.web.framework.helpers import time_ago, grids, iff
from galaxy.util.sanitize_html import sanitize_html
class VisualizationListGrid( grids.Grid ):
# Grid definition
- title = "Visualizations"
+ title = "Saved Visualizations"
model_class = model.Visualization
default_sort_key = "-update_time"
+ default_filter = dict( title="All", deleted="False", tags="All", sharing="All" )
columns = [
- grids.GridColumn( "Title", key="title", attach_popup=True,
+ grids.TextColumn( "Title", key="title", model_class=model.Visualization, attach_popup=True,
link=( lambda item: dict( controller="tracks", action="browser", id=item.id ) ) ),
- grids.GridColumn( "Type", key="type" ),
+ grids.TextColumn( "Type", key="type", model_class=model.Visualization ),
+ grids.IndividualTagsColumn( "Tags", "tags", model.Visualization, model.VisualizationTagAssociation, filterable="advanced", grid_name="VisualizationListGrid" ),
+ grids.SharingStatusColumn( "Sharing", key="sharing", model_class=model.Visualization, filterable="advanced", sortable=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
- ]
- ## global_actions = [
- ## grids.GridAction( "Add new page", dict( action='create' ) )
- ## ]
+ ]
+ columns.append(
+ grids.MulticolFilterColumn(
+ "Search",
+ cols_to_filter=[ columns[0], columns[2] ],
+ key="free-text-search", visible=False, filterable="standard" )
+ )
operations = [
- grids.GridOperation( "View", allow_multiple=False, url_args=dict( controller="tracks", action='browser' ) ),
+ grids.GridOperation( "Edit content", allow_multiple=False, url_args=dict( controller='tracks', action='browser' ) ),
+ grids.GridOperation( "Edit attributes", allow_multiple=False, url_args=dict( action='edit') ),
+ grids.GridOperation( "Share or Publish", allow_multiple=False, condition=( lambda item: not item.deleted ), async_compatible=False ),
+ grids.GridOperation( "Delete", condition=( lambda item: not item.deleted ), async_compatible=True, confirm="Are you sure you want to delete this visualization?" ),
]
def apply_default_filter( self, trans, query, **kwargs ):
- return query.filter_by( user=trans.user )
+ return query.filter_by( user=trans.user, deleted=False )
+
+class VisualizationAllPublishedGrid( grids.Grid ):
+ # Grid definition
+ use_panels = True
+ use_async = True
+ title = "Published Visualizations"
+ model_class = model.Visualization
+ default_sort_key = "-update_time"
+ default_filter = dict( title="All", username="All" )
+ columns = [
+ grids.PublicURLColumn( "Title", key="title", model_class=model.Visualization, filterable="advanced" ),
+ grids.OwnerAnnotationColumn( "Annotation", key="annotation", model_class=model.Visualization, model_annotation_association_class=model.VisualizationAnnotationAssociation, filterable="advanced" ),
+ grids.OwnerColumn( "Owner", key="username", model_class=model.User, filterable="advanced", sortable=False ),
+ grids.CommunityTagsColumn( "Community Tags", "tags", model.Visualization, model.VisualizationTagAssociation, filterable="advanced", grid_name="VisualizationAllPublishedGrid" ),
+ grids.GridColumn( "Last Updated", key="update_time", format=time_ago )
+ ]
+ columns.append(
+ grids.MulticolFilterColumn(
+ "Search",
+ cols_to_filter=[ columns[0], columns[1], columns[2], columns[3] ],
+ key="free-text-search", visible=False, filterable="standard" )
+ )
+ def build_initial_query( self, session ):
+ # Join so that searching history.user makes sense.
+ return session.query( self.model_class ).join( model.User.table )
+ def apply_default_filter( self, trans, query, **kwargs ):
+ return query.filter( self.model_class.deleted==False ).filter( self.model_class.published==True )
-class VisualizationController( BaseController ):
- list_grid = VisualizationListGrid()
+
+class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVisualization ):
+ _user_list_grid = VisualizationListGrid()
+ _published_list_grid = VisualizationAllPublishedGrid()
+
@web.expose
- @web.require_login()
- def index( self, trans, *args, **kwargs ):
- return trans.fill_template( "panels.mako", grid=self.list_grid( trans, *args, **kwargs ), active_view='visualization', main_url=url_for( action='list' ) )
+ def list_published( self, trans, *args, **kwargs ):
+ grid = self._published_list_grid( trans, **kwargs )
+ if 'async' in kwargs:
+ return grid
+ else:
+ # Render grid wrapped in panels
+ return trans.fill_template( "visualization/list_published.mako", grid=grid )
+
+ @web.expose
+ @web.require_login("use Galaxy visualizations")
+ def list( self, trans, *args, **kwargs ):
+ # Handle operation
+ if 'operation' in kwargs and 'id' in kwargs:
+ session = trans.sa_session
+ operation = kwargs['operation'].lower()
+ ids = util.listify( kwargs['id'] )
+ for id in ids:
+ item = session.query( model.Visualization ).get( trans.security.decode_id( id ) )
+ if operation == "delete":
+ item.deleted = True
+ if operation == "share or publish":
+ return self.sharing( trans, **kwargs )
+ session.flush()
+
+ # Build list of visualizations shared with user.
+ shared_by_others = trans.sa_session \
+ .query( model.VisualizationUserShareAssociation ) \
+ .filter_by( user=trans.get_user() ) \
+ .join( model.Visualization.table ) \
+ .filter( model.Visualization.deleted == False ) \
+ .order_by( desc( model.Visualization.update_time ) ) \
+ .all()
+
+ return trans.fill_template( "visualization/list.mako", grid=self._user_list_grid( trans, *args, **kwargs ), shared_by_others=shared_by_others )
+
+ @web.expose
+ @web.require_login( "modify Galaxy visualizations" )
+ def set_slug_async( self, trans, id, new_slug ):
+ """ Set item slug asynchronously. """
+ visualization = self.get_visualization( trans, id )
+ if visualization:
+ visualization.slug = new_slug
+ trans.sa_session.flush()
+ return visualization.slug
+
+ @web.expose
+ @web.require_login( "share Galaxy visualizations" )
+ def sharing( self, trans, id, **kwargs ):
+ """ Handle visualization sharing. """
+
+ # Get session and visualization.
+ session = trans.sa_session
+ visualization = trans.sa_session.query( model.Visualization ).get( trans.security.decode_id( id ) )
+
+ # Do operation on visualization.
+ if 'make_accessible_via_link' in kwargs:
+ self._make_item_accessible( trans.sa_session, visualization )
+ elif 'make_accessible_and_publish' in kwargs:
+ self._make_item_accessible( trans.sa_session, visualization )
+ visualization.published = True
+ elif 'publish' in kwargs:
+ visualization.published = True
+ elif 'disable_link_access' in kwargs:
+ visualization.importable = False
+ elif 'unpublish' in kwargs:
+ visualization.published = False
+ elif 'disable_link_access_and_unpublish' in kwargs:
+ visualization.importable = visualization.published = False
+ elif 'unshare_user' in kwargs:
+ user = session.query( model.User ).get( trans.security.decode_id( kwargs['unshare_user' ] ) )
+ if not user:
+ error( "User not found for provided id" )
+ association = session.query( model.VisualizationUserShareAssociation ) \
+ .filter_by( user=user, visualization=visualization ).one()
+ session.delete( association )
+
+ session.flush()
+
+ return trans.fill_template( "/sharing_base.mako", item=visualization )
+
+ @web.expose
+ @web.require_login( "share Galaxy visualizations" )
+ def share( self, trans, id=None, email="", **kwd ):
+ """ Handle sharing a visualization with a particular user. """
+ msg = mtype = None
+ visualization = trans.sa_session.query( model.Visualization ).get( trans.security.decode_id( id ) )
+ if email:
+ other = trans.sa_session.query( model.User ) \
+ .filter( and_( model.User.table.c.email==email,
+ model.User.table.c.deleted==False ) ) \
+ .first()
+ if not other:
+ mtype = "error"
+ msg = ( "User '%s' does not exist" % email )
+ elif other == trans.get_user():
+ mtype = "error"
+ msg = ( "You cannot share a visualization with yourself" )
+ elif trans.sa_session.query( model.VisualizationUserShareAssociation ) \
+ .filter_by( user=other, visualization=visualization ).count() > 0:
+ mtype = "error"
+ msg = ( "Visualization already shared with '%s'" % email )
+ else:
+ share = model.VisualizationUserShareAssociation()
+ share.visualization = visualization
+ share.user = other
+ session = trans.sa_session
+ session.add( share )
+ self.create_item_slug( session, visualization )
+ session.flush()
+ trans.set_message( "Visualization '%s' shared with user '%s'" % ( visualization.title, other.email ) )
+ return trans.response.send_redirect( url_for( action='sharing', id=id ) )
+ return trans.fill_template( "/share_base.mako",
+ message = msg,
+ messagetype = mtype,
+ item=visualization,
+ email=email )
+
+
+ @web.expose
+ def display_by_username_and_slug( self, trans, username, slug ):
+ """ Display visualization based on a username and slug. """
+
+ # Get visualization.
+ session = trans.sa_session
+ user = session.query( model.User ).filter_by( username=username ).first()
+ visualization = trans.sa_session.query( model.Visualization ).filter_by( user=user, slug=slug, deleted=False ).first()
+ if visualization is None:
+ raise web.httpexceptions.HTTPNotFound()
+ # Security check raises error if user cannot access visualization.
+ self.security_check( trans.get_user(), visualization, False, True)
+ return trans.fill_template_mako( "visualization/display.mako", item=visualization, item_data=None, content_only=True )
+
+ @web.expose
+ @web.json
+ @web.require_login( "get item name and link" )
+ def get_name_and_link_async( self, trans, id=None ):
+ """ Returns visualization's name and link. """
+ visualization = self.get_visualization( trans, id )
+
+ if self.create_item_slug( trans.sa_session, visualization ):
+ trans.sa_session.flush()
+ return_dict = { "name" : visualization.title, "link" : url_for( action="display_by_username_and_slug", username=visualization.user.username, slug=visualization.slug ) }
+ return return_dict
+
+ @web.expose
+ @web.require_login("get item content asynchronously")
+ def get_item_content_async( self, trans, id ):
+ """ Returns item content in HTML format. """
+ pass
+
+ @web.expose
+ @web.require_login( "create visualizations" )
+ def create( self, trans, visualization_title="", visualization_slug="", visualization_annotation="" ):
+ """
+ Create a new visualization
+ """
+ user = trans.get_user()
+ visualization_title_err = visualization_slug_err = visualization_annotation_err = ""
+ if trans.request.method == "POST":
+ if not visualization_title:
+ visualization_title_err = "visualization name is required"
+ elif not visualization_slug:
+ visualization_slug_err = "visualization id is required"
+ elif not VALID_SLUG_RE.match( visualization_slug ):
+ visualization_slug_err = "visualization identifier must consist of only lowercase letters, numbers, and the '-' character"
+ elif trans.sa_session.query( model.Visualization ).filter_by( user=user, slug=visualization_slug, deleted=False ).first():
+ visualization_slug_err = "visualization id must be unique"
+ else:
+ # Create the new stored visualization
+ visualization = model.Visualization()
+ visualization.title = visualization_title
+ visualization.slug = visualization_slug
+ visualization_annotation = sanitize_html( visualization_annotation, 'utf-8', 'text/html' )
+ self.add_item_annotation( trans, visualization, visualization_annotation )
+ visualization.user = user
+ # And the first (empty) visualization revision
+ visualization_revision = model.VisualizationRevision()
+ visualization_revision.title = visualization_title
+ visualization_revision.visualization = visualization
+ visualization.latest_revision = visualization_revision
+ visualization_revision.content = ""
+ # Persist
+ session = trans.sa_session
+ session.add( visualization )
+ session.flush()
+ # Display the management visualization
+ ## trans.set_message( "Visualization '%s' created" % visualization.title )
+ return trans.response.send_redirect( web.url_for( action='list' ) )
+ return trans.show_form(
+ web.FormBuilder( web.url_for(), "Create new visualization", submit_text="Submit" )
+ .add_text( "visualization_title", "Visualization title", value=visualization_title, error=visualization_title_err )
+ .add_text( "visualization_slug", "Visualization identifier", value=visualization_slug, error=visualization_slug_err,
+ help="""A unique identifier that will be used for
+ public links to this visualization. A default is generated
+ from the visualization title, but can be edited. This field
+ must contain only lowercase letters, numbers, and
+ the '-' character.""" )
+ .add_text( "visualization_annotation", "Visualization annotation", value=visualization_annotation, error=visualization_annotation_err,
+ help="A description of the visualization; annotation is shown alongside published visualizations."),
+ template="visualization/create.mako" )
+
+ @web.expose
+ @web.require_login( "edit visualizations" )
+ def edit( self, trans, id, visualization_title="", visualization_slug="", visualization_annotation="" ):
+ """
+ Edit a visualization's attributes.
+ """
+ encoded_id = id
+ id = trans.security.decode_id( id )
+ session = trans.sa_session
+ visualization = session.query( model.Visualization ).get( id )
+ user = trans.user
+ assert visualization.user == user
+ visualization_title_err = visualization_slug_err = visualization_annotation_err = ""
+ if trans.request.method == "POST":
+ if not visualization_title:
+ visualization_title_err = "Visualization name is required"
+ elif not visualization_slug:
+ visualization_slug_err = "Visualization id is required"
+ elif not VALID_SLUG_RE.match( visualization_slug ):
+ visualization_slug_err = "Visualization identifier must consist of only lowercase letters, numbers, and the '-' character"
+ elif visualization_slug != visualization.slug and trans.sa_session.query( model.Visualization ).filter_by( user=user, slug=visualization_slug, deleted=False ).first():
+ visualization_slug_err = "Visualization id must be unique"
+ elif not visualization_annotation:
+ visualization_annotation_err = "Visualization annotation is required"
+ else:
+ visualization.title = visualization_title
+ visualization.slug = visualization_slug
+ visualization_annotation = sanitize_html( visualization_annotation, 'utf-8', 'text/html' )
+ self.add_item_annotation( trans, visualization, visualization_annotation )
+ session.flush()
+ # Redirect to visualization list.
+ return trans.response.send_redirect( web.url_for( action='list' ) )
+ else:
+ visualization_title = visualization.title
+ # Create slug if it's not already set.
+ if visualization.slug is None:
+ self.create_item_slug( trans.sa_session, visualization )
+ visualization_slug = visualization.slug
+ visualization_annotation = self.get_item_annotation_str( trans.sa_session, trans.get_user(), visualization )
+ if not visualization_annotation:
+ visualization_annotation = ""
+ return trans.show_form(
+ web.FormBuilder( web.url_for( id=encoded_id ), "Edit visualization attributes", submit_text="Submit" )
+ .add_text( "visualization_title", "Visualization title", value=visualization_title, error=visualization_title_err )
+ .add_text( "visualization_slug", "Visualization identifier", value=visualization_slug, error=visualization_slug_err,
+ help="""A unique identifier that will be used for
+ public links to this visualization. A default is generated
+ from the visualization title, but can be edited. This field
+ must contain only lowercase letters, numbers, and
+ the '-' character.""" )
+ .add_text( "visualization_annotation", "Visualization annotation", value=visualization_annotation, error=visualization_annotation_err,
+ help="A description of the visualization; annotation is shown alongside published visualizations."),
+ template="visualization/create.mako" )
# @web.expose
# @web.require_login()
@@ -42,6 +332,6 @@
# # Build grid
# grid = self.list( trans, *args, **kwargs )
# # Render grid wrapped in panels
- # return trans.fill_template( "page/index.mako", grid=grid )
+ # return trans.fill_template( "visualization/index.mako", grid=grid )
\ No newline at end of file
diff -r 582fd1777763 -r c3eccab29814 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Thu Mar 11 15:54:13 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Fri Mar 12 09:37:22 2010 -0500
@@ -123,7 +123,7 @@
# Legacy issue: all shared workflows must have slugs.
slug_set = False
for workflow_assoc in shared_by_others:
- slug_set = self.set_item_slug( trans.sa_session, workflow_assoc.stored_workflow )
+ slug_set = self.create_item_slug( trans.sa_session, workflow_assoc.stored_workflow )
if slug_set:
trans.sa_session.flush()
@@ -224,7 +224,7 @@
share.user = other
session = trans.sa_session
session.add( share )
- self.set_item_slug( session, stored )
+ self.create_item_slug( session, stored )
session.flush()
trans.set_message( "Workflow '%s' shared with user '%s'" % ( stored.name, other.email ) )
return trans.response.send_redirect( url_for( controller='workflow', action='sharing', id=id ) )
@@ -401,7 +401,7 @@
""" Returns workflow's name and link. """
stored = self.get_stored_workflow( trans, id )
- if self.set_item_slug( trans.sa_session, stored ):
+ if self.create_item_slug( trans.sa_session, stored ):
trans.sa_session.flush()
return_dict = { "name" : stored.name, "link" : url_for( action="display_by_username_and_slug", username=stored.user.username, slug=stored.slug ) }
return return_dict
diff -r 582fd1777763 -r c3eccab29814 templates/base_panels.mako
--- a/templates/base_panels.mako Thu Mar 11 15:54:13 2010 -0500
+++ b/templates/base_panels.mako Fri Mar 12 09:37:22 2010 -0500
@@ -207,7 +207,7 @@
<ul>
<li><a href="${h.url_for( controller='/tracks', action='index' )}">Build track browser</a></li>
<li><hr style="color: inherit; background-color: gray"/></li>
- <li><a href="${h.url_for( controller='/visualization', action='index' )}">Stored visualizations</a></li>
+ <li><a href="${h.url_for( controller='/visualization', action='list' )}">Stored visualizations</a></li>
</ul>
</div>
</td>
diff -r 582fd1777763 -r c3eccab29814 templates/display_common.mako
--- a/templates/display_common.mako Thu Mar 11 15:54:13 2010 -0500
+++ b/templates/display_common.mako Fri Mar 12 09:37:22 2010 -0500
@@ -18,8 +18,11 @@
<%def name="get_item_name( item )">
<%
+ # Start with exceptions, end with default.
if type( item ) is model.Page:
return item.title
+ elif type( item ) is model.Visualization:
+ return item.title
if hasattr( item, 'get_display_name'):
return item.get_display_name()
return item.name
@@ -29,7 +32,7 @@
## Get plural display name for a class.
<%def name="get_class_plural_display_name( a_class )">
<%
- ## Start with exceptions, end with default.
+ # Start with exceptions, end with default.
if a_class is model.History:
return "Histories"
elif a_class is model.FormDefinitionCurrent:
@@ -89,6 +92,8 @@
return "dataset"
elif isinstance( item, model.Page ):
return "page"
+ elif isinstance( item, model.Visualization ):
+ return "visualization"
%>
</%def>
diff -r 582fd1777763 -r c3eccab29814 templates/page/create.mako
--- a/templates/page/create.mako Thu Mar 11 15:54:13 2010 -0500
+++ b/templates/page/create.mako Fri Mar 12 09:37:22 2010 -0500
@@ -8,8 +8,7 @@
var page_slug = $("input[name=page_slug]");
page_name.keyup(function(){
page_slug.val( $(this).val().replace(/\s+/g,'-').replace(/[^a-zA-Z0-9\-]/g,'').toLowerCase() )
- });
-
+ });
})
</script>
</%def>
\ No newline at end of file
diff -r 582fd1777763 -r c3eccab29814 templates/panels.mako
--- a/templates/panels.mako Thu Mar 11 15:54:13 2010 -0500
+++ b/templates/panels.mako Fri Mar 12 09:37:22 2010 -0500
@@ -10,11 +10,9 @@
</%def>
<%def name="center_panel()">
-
<div style="overflow: auto; height: 100%;">
<div style="padding: 10px">
${grid}
</div>
</div>
-
</%def>
diff -r 582fd1777763 -r c3eccab29814 templates/visualization/create.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/visualization/create.mako Fri Mar 12 09:37:22 2010 -0500
@@ -0,0 +1,14 @@
+<%inherit file="/form.mako"/>
+
+<%def name="javascripts()">
+${parent.javascripts()}
+<script type="text/javascript">
+$(function(){
+ var visualization_name = $("input[name=visualization_title]");
+ var visualization_slug = $("input[name=visualization_slug]");
+ visualization_name.keyup(function(){
+ visualization_slug.val( $(this).val().replace(/\s+/g,'-').replace(/[^a-zA-Z0-9\-]/g,'').toLowerCase() )
+ });
+})
+</script>
+</%def>
\ No newline at end of file
diff -r 582fd1777763 -r c3eccab29814 templates/visualization/display.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/visualization/display.mako Fri Mar 12 09:37:22 2010 -0500
@@ -0,0 +1,19 @@
+<%inherit file="/display_base.mako"/>
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ ## Need visualization JS.
+</%def>
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ ## Need visualization CSS.
+</%def>
+
+<%def name="render_item_links( visualization )">
+ ## TODO
+</%def>
+
+<%def name="render_item( visualization, visualization_data )">
+ ## TODO
+</%def>
\ No newline at end of file
diff -r 582fd1777763 -r c3eccab29814 templates/visualization/list.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/visualization/list.mako Fri Mar 12 09:37:22 2010 -0500
@@ -0,0 +1,52 @@
+<%inherit file="/base_panels.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="visualization"
+ self.message_box_visible=False
+%>
+</%def>
+
+<%def name="center_panel()">
+
+ <div style="overflow: auto; height: 100%;">
+ <div class="page-container" style="padding: 10px;">
+ ${grid}
+
+ <br><br>
+ <h2>Visualizations shared with you by others</h2>
+
+ %if shared_by_others:
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>Title</th>
+ <th>Owner</th>
+ <th></th>
+ </tr>
+ %for i, association in enumerate( shared_by_others ):
+ <% visualization = association.visualization %>
+ <tr>
+ <td>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( action='display_by_username_and_slug', username=visualization.user.username, slug=visualization.slug)}">${visualization.title}</a>
+ </td>
+ <td>${visualization.user.username}</td>
+ <td>
+ <div popupmenu="shared-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='display_by_username_and_slug', username=visualization.user.username, slug=visualization.slug)}" target="_top">View</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
+
+ No visualizations have been shared with you.
+
+ %endif
+
+ </div>
+ </div>
+
+</%def>
diff -r 582fd1777763 -r c3eccab29814 templates/visualization/list_published.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/visualization/list_published.mako Fri Mar 12 09:37:22 2010 -0500
@@ -0,0 +1,36 @@
+<%inherit file="/base_panels.mako"/>
+
+<%def name="init()">
+<%
+ self.has_left_panel=False
+ self.has_right_panel=False
+ self.active_view="page"
+ self.message_box_visible=False
+%>
+</%def>
+
+<%def name="title()">
+ Galaxy :: Published Visualizations
+</%def>
+
+<%def name="stylesheets()">
+ ${parent.stylesheets()}
+ <style>
+ .grid td {
+ min-width: 100px;
+ }
+ </style>
+</%def>
+
+<%def name="center_panel()">
+
+ ## <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${h.url_for( controller="page", action="list" )}"> </iframe>
+
+ <div style="overflow: auto; height: 100%;">
+ <div class="page-container" style="padding: 10px;">
+ ${unicode( grid, 'utf-8' )}
+ </div>
+ </div>
+
+
+</%def>
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/582fd1777763
changeset: 3522:582fd1777763
user: Kelly Vincent <kpvincent(a)bx.psu.edu>
date: Thu Mar 11 15:54:13 2010 -0500
description:
Modified BWA output files so last two tests will pass
diffstat:
test-data/bwa_wrapper_out2.sam | 2 +-
test-data/bwa_wrapper_out3.sam | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diffs (14 lines):
diff -r f13d85256124 -r 582fd1777763 test-data/bwa_wrapper_out2.sam
--- a/test-data/bwa_wrapper_out2.sam Thu Mar 11 14:35:36 2010 -0500
+++ b/test-data/bwa_wrapper_out2.sam Thu Mar 11 15:54:13 2010 -0500
@@ -1,1 +1,1 @@
-081017-and-081020:1:1:1715:1759 16 phiX 322 25 36M * 0 0 GATATTTTAAAGGAGCGTGGATTACTATCTGAGTCC B&&I13A$G$*%$IIIIIII9(.+5$IIIIIII#II XT:A:U NM:i:2 X0:i:1 XM:i:2 XO:i:0 XG:i:0 MD:Z:2C8A24
+081017-and-081020:1:1:1715:1759 16 phiX 322 25 36M * 0 0 GATATTTTAAAGGAGCGTGGATTACTATCTGAGTCC B&&I13A$G$*%$IIIIIII9(.+5$IIIIIII#II XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:2 XO:i:0 XG:i:0 MD:Z:2C8A24
diff -r f13d85256124 -r 582fd1777763 test-data/bwa_wrapper_out3.sam
--- a/test-data/bwa_wrapper_out3.sam Thu Mar 11 14:35:36 2010 -0500
+++ b/test-data/bwa_wrapper_out3.sam Thu Mar 11 15:54:13 2010 -0500
@@ -1,2 +1,2 @@
-081017-and-081020:1:1:1715:1759 113 PHIX174 322 25 18M = 340 18 GATATTTTAAAGGAGCGT B&&I13A$G$*%$IIIII XT:A:U NM:i:2 SM:i:25 AM:i:25 X0:i:1 XM:i:2 XO:i:0 XG:i:0 MD:Z:2C8A6
-081017-and-081020:1:1:1715:1759 177 PHIX174 340 37 18M = 322 -18 GGATTACTATCTGAGTCC II9(.+5$IIIIIII#II XT:A:U NM:i:0 SM:i:37 AM:i:25 X0:i:1 XM:i:0 XO:i:0 XG:i:0 MD:Z:18
+081017-and-081020:1:1:1715:1759 113 PHIX174 322 25 18M = 340 18 GATATTTTAAAGGAGCGT B&&I13A$G$*%$IIIII XT:A:U NM:i:2 SM:i:25 AM:i:25 X0:i:1 X1:i:0 XM:i:2 XO:i:0 XG:i:0 MD:Z:2C8A6
+081017-and-081020:1:1:1715:1759 177 PHIX174 340 37 18M = 322 -18 GGATTACTATCTGAGTCC II9(.+5$IIIIIII#II XT:A:U NM:i:0 SM:i:37 AM:i:25 X0:i:1 X1:i:0 XM:i:0 XO:i:0 XG:i:0 MD:Z:18
1
0
18 Mar '10
details: http://www.bx.psu.edu/hg/galaxy/rev/f13d85256124
changeset: 3521:f13d85256124
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Thu Mar 11 14:35:36 2010 -0500
description:
Display Application framework enhancements.
Add the ability for display applications to be populated dynamically based upon the content of (e.g. tabular) files.
Display application links can be filtered by various attributes, including e.g. dataset dbkey matching from field in a file or an attribute matching a Galaxy application configuration setting.
Param and Data URL values can now be generated dynamically, allowing e.g unique base filenames to be created and used.
See updated xml configurations in /display_applications/ for examples of syntax.
diffstat:
datatypes_conf.xml.sample | 9 +-
display_applications/ucsc/bam.xml | 34 +++++-
display_applications/ucsc/interval_as_bed.xml | 63 +++++++++++-
lib/galaxy/datatypes/data.py | 9 +
lib/galaxy/datatypes/display_applications/application.py | 78 ++++++++++++++-
lib/galaxy/datatypes/display_applications/parameters.py | 13 +-
lib/galaxy/datatypes/registry.py | 34 ++++--
lib/galaxy/model/__init__.py | 3 +
templates/root/history_common.mako | 2 +-
tool-data/shared/bx/bx_build_sites.txt | 2 +-
10 files changed, 205 insertions(+), 42 deletions(-)
diffs (468 lines):
diff -r 262b16c8e277 -r f13d85256124 datatypes_conf.xml.sample
--- a/datatypes_conf.xml.sample Thu Mar 11 13:51:53 2010 -0500
+++ b/datatypes_conf.xml.sample Thu Mar 11 14:35:36 2010 -0500
@@ -15,10 +15,7 @@
<!-- <display file="ucsc/interval_as_bed.xml" /> -->
<display file="genetrack.xml" />
</datatype>
- <datatype extension="bedstrict" type="galaxy.datatypes.interval:BedStrict">
- <display file="ucsc/interval_as_bed.xml" />
- <display file="genetrack.xml" />
- </datatype>
+ <datatype extension="bedstrict" type="galaxy.datatypes.interval:BedStrict" />
<datatype extension="binseq.zip" type="galaxy.datatypes.binary:Binseq" mimetype="application/zip" display_in_upload="true"/>
<datatype extension="len" type="galaxy.datatypes.chrominfo:ChromInfo" display_in_upload="true">
<!-- no converters yet -->
@@ -51,8 +48,8 @@
<converter file="interval_to_bed_converter.xml" target_datatype="bed"/>
<converter file="interval_to_bedstrict_converter.xml" target_datatype="bedstrict"/>
<indexer file="interval_awk.xml" />
- <!-- <display file="ucsc/interval_as_bed.xml" /> -->
- <display file="genetrack.xml" />
+ <!-- <display file="ucsc/interval_as_bed.xml" inherit="True" /> -->
+ <display file="genetrack.xml" inherit="True"/>
</datatype>
<datatype extension="jpg" type="galaxy.datatypes.images:Image" mimetype="image/jpeg"/>
<datatype extension="laj" type="galaxy.datatypes.images:Laj"/>
diff -r 262b16c8e277 -r f13d85256124 display_applications/ucsc/bam.xml
--- a/display_applications/ucsc/bam.xml Thu Mar 11 13:51:53 2010 -0500
+++ b/display_applications/ucsc/bam.xml Thu Mar 11 14:35:36 2010 -0500
@@ -1,8 +1,32 @@
<display id="ucsc_bam" version="1.0.0" name="display at UCSC">
- <link id="main" name="main">
- <url>http://genome.ucsc.edu/cgi-bin/hgTracks?db=${qp($bam_file.dbkey)}&hgt.c…</url>
- <param type="data" name="bam_file" url="galaxy.bam" strip_https="True" />
- <param type="data" name="bai_file" url="galaxy.bam.bai" metadata="bam_index" strip_https="True" /><!-- UCSC expects index file to exist as bam_file_name.bai -->
+ <!-- Load links from file: one line to one link -->
+ <dynamic_links from_file="tool-data/shared/ucsc/ucsc_build_sites.txt" skip_startswith="#" id="0" name="0">
+ <!-- Define parameters by column from file, allow splitting on builds -->
+ <dynamic_param name="site_id" value="0"/>
+ <dynamic_param name="ucsc_link" value="1"/>
+ <dynamic_param name="builds" value="2" split="True" separator="," />
+ <!-- Filter out some of the links based upon matching site_id to a Galaxy application configuration parameter and by dataset dbkey -->
+ <filter>${site_id in $APP.config.ucsc_display_sites}</filter>
+ <filter>${dataset.dbkey in $builds}</filter>
+ <!-- We define url and params as normal, but values defined in dynamic_param are available by specified name -->
+ <url>${ucsc_link}db=${qp($bam_file.dbkey)}&hgt.customText=${qp($track.url)}</url>
+ <param type="data" name="bam_file" url="galaxy_${DATASET_HASH}.bam" strip_https="True" />
+ <param type="data" name="bai_file" url="galaxy_${DATASET_HASH}.bam.bai" metadata="bam_index" strip_https="True" /><!-- UCSC expects index file to exist as bam_file_name.bai -->
<param type="template" name="track" viewable="True" strip_https="True">track type=bam name="${bam_file.name}" bigDataUrl=${bam_file.url} db=${bam_file.dbkey}</param>
- </link>
+ </dynamic_links>
+ <!-- Load links from file: one line to one link -->
+ <dynamic_links from_file="tool-data/shared/bx/bx_build_sites.txt" skip_startswith="#" id="3" name="3">
+ <!-- Define parameters by column from file, allow splitting on builds -->
+ <dynamic_param name="site_id" value="0"/>
+ <dynamic_param name="ucsc_link" value="1"/>
+ <dynamic_param name="builds" value="2" split="True" separator="," />
+ <!-- Filter out some of the links based upon matching site_id to a Galaxy application configuration parameter and by dataset dbkey -->
+ <filter>${site_id in $APP.config.bx_display_sites}</filter>
+ <filter>${dataset.dbkey in $builds}</filter>
+ <!-- We define url and params as normal, but values defined in dynamic_param are available by specified name -->
+ <url>${ucsc_link}db=${qp($bam_file.dbkey)}&hgt.customText=${qp($track.url)}</url>
+ <param type="data" name="bam_file" url="galaxy_${DATASET_HASH}.bam" strip_https="True" />
+ <param type="data" name="bai_file" url="galaxy_${DATASET_HASH}.bam.bai" metadata="bam_index" strip_https="True" /><!-- UCSC expects index file to exist as bam_file_name.bai -->
+ <param type="template" name="track" viewable="True" strip_https="True">track type=bam name="${bam_file.name}" bigDataUrl=${bam_file.url} db=${bam_file.dbkey}</param>
+ </dynamic_links>
</display>
diff -r 262b16c8e277 -r f13d85256124 display_applications/ucsc/interval_as_bed.xml
--- a/display_applications/ucsc/interval_as_bed.xml Thu Mar 11 13:51:53 2010 -0500
+++ b/display_applications/ucsc/interval_as_bed.xml Thu Mar 11 14:35:36 2010 -0500
@@ -1,7 +1,16 @@
-<display id="ucsc_interval_as_bed" version="1.0.0" name="display at UCSC">
- <link id="main" name="main">
- <url>http://genome.ucsc.edu/cgi-bin/hgTracks?db=${qp($bed_file.dbkey)}&posit…</url>
- <param type="data" name="bed_file" url="galaxy.bed" format="bedstrict"/> <!-- Galaxy allows BED files to contain non-standard fields beyond the first 3 columns, UCSC does not: force use of converter which will make strict BED6+ file -->
+<display id="ucsc_interval_as_bed" version="1.0.0" name="display at UCSC" inherit="True">
+ <!-- Load links from file: one line to one link -->
+ <dynamic_links from_file="tool-data/shared/ucsc/ucsc_build_sites.txt" skip_startswith="#" id="0" name="0">
+ <!-- Define parameters by column from file, allow splitting on builds -->
+ <dynamic_param name="site_id" value="0"/>
+ <dynamic_param name="ucsc_link" value="1"/>
+ <dynamic_param name="builds" value="2" split="True" separator="," />
+ <!-- Filter out some of the links based upon matching site_id to a Galaxy application configuration parameter and by dataset dbkey -->
+ <filter>${site_id in $APP.config.ucsc_display_sites}</filter>
+ <filter>${dataset.dbkey in $builds}</filter>
+ <!-- We define url and params as normal, but values defined in dynamic_param are available by specified name -->
+ <url>${ucsc_link}db=${qp($bed_file.dbkey)}&position=${position.qp}&hgt.customText=${bed_file.qp}</url>
+ <param type="data" name="bed_file" url="galaxy_${DATASET_HASH}.bed" format="bedstrict"/> <!-- Galaxy allows BED files to contain non-standard fields beyond the first 3 columns, UCSC does not: force use of converter which will make strict BED6+ file -->
<param type="template" name="position" strip="True" >
#set line_count = 0
#set chrom = None
@@ -33,5 +42,49 @@
:-
#end if
</param>
- </link>
+ </dynamic_links>
+ <!-- Load links from file: one line to one link -->
+ <dynamic_links from_file="tool-data/shared/bx/bx_build_sites.txt" skip_startswith="#" id="3" name="3">
+ <!-- Define parameters by column from file, allow splitting on builds -->
+ <dynamic_param name="site_id" value="0"/>
+ <dynamic_param name="ucsc_link" value="1"/>
+ <dynamic_param name="builds" value="2" split="True" separator="," />
+ <!-- Filter out some of the links based upon matching site_id to a Galaxy application configuration parameter and by dataset dbkey -->
+ <filter>${site_id in $APP.config.bx_display_sites}</filter>
+ <filter>${dataset.dbkey in $builds}</filter>
+ <!-- We define url and params as normal, but values defined in dynamic_param are available by specified name -->
+ <url>${ucsc_link}db=${qp($bed_file.dbkey)}&position=${position.qp}&hgt.customText=${bed_file.qp}</url>
+ <param type="data" name="bed_file" url="galaxy_${DATASET_HASH}.bed" format="bedstrict"/> <!-- Galaxy allows BED files to contain non-standard fields beyond the first 3 columns, UCSC does not: force use of converter which will make strict BED6+ file -->
+ <param type="template" name="position" strip="True" >
+#set line_count = 0
+#set chrom = None
+#set start = float( 'inf' )
+#set end = 0
+#for $line in open( $bed_file.file_name ):
+ #if $line_count > 10: ##10 max lines to check for view port
+ #break
+ #end if
+ #if not $line.startswith( "#" ):
+ #set $fields = $line.split( "\t" )
+ #try:
+ #if len( $fields ) >= max( $bed_file.metadata.startCol, $bed_file.metadata.endCol, $bed_file.metadata.chromCol ):
+ #if $chrom is None or $fields[ $bed_file.metadata.chromCol - 1 ] == $chrom:
+ #set chrom = $fields[ $bed_file.metadata.chromCol - 1 ]
+ #set start = min( $start, int( $fields[ $bed_file.metadata.startCol - 1 ] ) )
+ #set end = max( $end, int( $fields[ $bed_file.metadata.endCol - 1 ] ) )
+ #end if
+ #end if
+ #except:
+ #pass
+ #end try
+ #end if
+ #set line_count += 1
+#end for
+#if $chrom is not None:
+${chrom}:${start}-${end + 1}
+#else:
+:-
+#end if
+ </param>
+ </dynamic_links>
</display>
diff -r 262b16c8e277 -r f13d85256124 lib/galaxy/datatypes/data.py
--- a/lib/galaxy/datatypes/data.py Thu Mar 11 13:51:53 2010 -0500
+++ b/lib/galaxy/datatypes/data.py Thu Mar 11 14:35:36 2010 -0500
@@ -205,6 +205,15 @@
"""New style display applications"""
assert display_application.id not in self.display_applications, 'Attempted to add a display application twice'
self.display_applications[ display_application.id ] = display_application
+ def get_display_application( self, key, default = None ):
+ return self.display_applications.get( key, default )
+ def get_display_applications_by_dataset( self, dataset, trans ):
+ rval = odict()
+ for key, value in self.display_applications.iteritems():
+ value = value.filter_by_dataset( dataset, trans )
+ if value.links:
+ rval[key] = value
+ return rval
def get_display_types(self):
"""Returns display types available"""
return self.supported_display_apps.keys()
diff -r 262b16c8e277 -r f13d85256124 lib/galaxy/datatypes/display_applications/application.py
--- a/lib/galaxy/datatypes/display_applications/application.py Thu Mar 11 13:51:53 2010 -0500
+++ b/lib/galaxy/datatypes/display_applications/application.py Thu Mar 11 14:35:36 2010 -0500
@@ -1,24 +1,27 @@
#Contains objects for using external display applications
-from galaxy.util import parse_xml
+from galaxy.util import parse_xml, string_as_bool
from galaxy.util.odict import odict
from galaxy.util.template import fill_template
from galaxy.web import url_for
from parameters import DisplayApplicationParameter, DEFAULT_DATASET_NAME
from urllib import quote_plus
from util import encode_dataset_user
+from copy import deepcopy
#Any basic functions that we want to provide as a basic part of parameter dict should be added to this dict
BASE_PARAMS = { 'qp': quote_plus, 'url_for':url_for } #url_for has route memory...
class DisplayApplicationLink( object ):
@classmethod
- def from_elem( cls, elem, display_application ):
+ def from_elem( cls, elem, display_application, other_values = None ):
rval = DisplayApplicationLink( display_application )
rval.id = elem.get( 'id', None )
assert rval.id, 'Link elements require a id.'
rval.name = elem.get( 'name', rval.id )
rval.url = elem.find( 'url' )
assert rval.url is not None, 'A url element must be provided for link elements.'
+ rval.other_values = other_values
+ rval.filters = elem.findall( 'filter' )
for param_elem in elem.findall( 'param' ):
param = DisplayApplicationParameter.from_elem( param_elem, rval )
assert param, 'Unable to load parameter from element: %s' % param_elem
@@ -36,13 +39,19 @@
dataset_hash, user_hash = encode_dataset_user( trans, data, None )
return url_for( controller = '/dataset', action = "display_application", dataset_id = dataset_hash, user_id = user_hash, app_name = self.display_application.id, link_name = self.id, app_action = None )
def get_inital_values( self, data, trans ):
- rval = odict( { 'BASE_URL': trans.request.base, 'APP': trans.app } ) #trans automatically appears as a response, need to add properties of trans that we want here
+ if self.other_values:
+ rval = odict( self.other_values )
+ else:
+ rval = odict()
+ rval.update( { 'BASE_URL': trans.request.base, 'APP': trans.app } ) #trans automatically appears as a response, need to add properties of trans that we want here
for key, value in BASE_PARAMS.iteritems(): #add helper functions/variables
rval[ key ] = value
rval[ DEFAULT_DATASET_NAME ] = data #always have the display dataset name available
return rval
def build_parameter_dict( self, data, dataset_hash, user_hash, trans ):
other_values = self.get_inital_values( data, trans )
+ other_values[ 'DATASET_HASH' ] = dataset_hash
+ other_values[ 'USER_HASH' ] = user_hash
for name, param in self.parameters.iteritems():
assert name not in other_values, "The display parameter '%s' has been defined more than once." % name
if param.ready( other_values ):
@@ -51,6 +60,51 @@
other_values[ name ] = None
return False, other_values #need to stop here, next params may need this value
return True, other_values #we built other_values, lets provide it as well, or else we will likely regenerate it in the next step
+ def filter_by_dataset( self, data, trans ):
+ context = self.get_inital_values( data, trans )
+ for filter_elem in self.filters:
+ if fill_template( filter_elem.text, context = context ) != filter_elem.get( 'value', 'True' ):
+ return False
+ return True
+
+class DynamicDisplayApplicationBuilder( object ):
+ @classmethod
+ def __init__( self, elem, display_application ):
+ rval = []
+ filename = elem.get( 'from_file', None )
+ assert filename is not None, 'Filename and id attributes required for dynamic_links'
+ skip_startswith = elem.get( 'skip_startswith', None )
+ separator = elem.get( 'separator', '\t' )
+ id_col = int( elem.get( 'id', None ) )
+ name_col = int( elem.get( 'name', id_col ) )
+ dynamic_params = {}
+ max_col = max( id_col, name_col )
+ for dynamic_param in elem.findall( 'dynamic_param' ):
+ name = dynamic_param.get( 'name' )
+ value = int( dynamic_param.get( 'value' ) )
+ split = string_as_bool( dynamic_param.get( 'split', False ) )
+ param_separator = dynamic_param.get( 'separator', ',' )
+ max_col = max( max_col, value )
+ dynamic_params[name] = { 'column': value, 'split': split, 'separator': param_separator }
+ for line in open( filename ):
+ if not skip_startswith or not line.startswith( skip_startswith ):
+ line = line.rstrip( '\n\r' )
+ fields = line.split( separator )
+ if len( fields ) >= max_col:
+ new_elem = deepcopy( elem )
+ new_elem.set( 'id', fields[id_col] )
+ new_elem.set( 'name', fields[name_col] )
+ dynamic_values = {}
+ for key, attributes in dynamic_params.iteritems():
+ value = fields[ attributes[ 'column' ] ]
+ if attributes['split']:
+ value = value.split( attributes['separator'] )
+ dynamic_values[key] = value
+ #now populate
+ rval.append( DisplayApplicationLink.from_elem( new_elem, display_application, other_values = dynamic_values ) )
+ self.links = rval
+ def __iter__( self ):
+ return iter( self.links )
class PopulatedDisplayApplicationLink( object ):
def __init__( self, display_application_link, data, dataset_hash, user_hash, trans ):
@@ -84,9 +138,11 @@
def display_url( self ):
assert self.display_ready(), 'Display is not yet ready, cannot generate display link'
return fill_template( self.link.url.text, context = self.parameters )
- def get_param_name_by_url( self, name ):
- assert name in self.link.url_param_name_map, "Unknown URL parameter name provided: %s" % name
- return self.link.url_param_name_map[ name ]
+ def get_param_name_by_url( self, url ):
+ for name, parameter in self.link.parameters.iteritems():
+ if parameter.build_url( self.parameters ) == url:
+ return name
+ raise ValueError( "Unknown URL parameter name provided: %s" % url )
class DisplayApplication( object ):
@classmethod
@@ -103,6 +159,9 @@
link = DisplayApplicationLink.from_elem( link_elem, rval )
if link:
rval.links[ link.id ] = link
+ for dynamic_links in elem.findall( 'dynamic_links' ):
+ for link in DynamicDisplayApplicationBuilder( dynamic_links, rval ):
+ rval.links[ link.id ] = link
return rval
def __init__( self, display_id, name, datatypes_registry, version = None ):
self.id = display_id
@@ -115,4 +174,9 @@
def get_link( self, link_name, data, dataset_hash, user_hash, trans ):
#returns a link object with data knowledge to generate links
return PopulatedDisplayApplicationLink( self.links[ link_name ], data, dataset_hash, user_hash, trans )
-
+ def filter_by_dataset( self, data, trans ):
+ filtered = DisplayApplication( self.id, self.name, self.datatypes_registry, version = self.version )
+ for link_name, link_value in self.links.iteritems():
+ if link_value.filter_by_dataset( data, trans ):
+ filtered.links[link_name] = link_value
+ return filtered
diff -r 262b16c8e277 -r f13d85256124 lib/galaxy/datatypes/display_applications/parameters.py
--- a/lib/galaxy/datatypes/display_applications/parameters.py Thu Mar 11 13:51:53 2010 -0500
+++ b/lib/galaxy/datatypes/display_applications/parameters.py Thu Mar 11 14:35:36 2010 -0500
@@ -35,6 +35,8 @@
return True
def is_preparing( self, other_values ):
return False
+ def build_url( self, other_values ):
+ return fill_template( self.url, context = other_values )
class DisplayApplicationDataParameter( DisplayApplicationParameter ):
""" Parameter that returns a file_name containing the requested content """
@@ -141,15 +143,16 @@
self.trans = trans
self._dataset_hash = dataset_hash
self._user_hash = user_hash
+ self._url = self.parameter.build_url( self.other_values )
def __str__( self ):
return str( self.value )
def mime_type( self ):
if self.parameter.mime_type is not None:
return self.parameter.mime_type
if self.parameter.guess_mime_type:
- mime, encoding = mimetypes.guess_type( self.parameter.url )
+ mime, encoding = mimetypes.guess_type( self._url )
if not mime:
- mime = self.trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( self.parameter.url )[ -1 ], None )
+ mime = self.trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( self._url )[ -1 ], None )
if mime:
return mime
return 'text/plain'
@@ -158,7 +161,7 @@
base_url = self.trans.request.base
if self.parameter.strip_https and base_url[ : 5].lower() == 'https':
base_url = "http%s" % base_url[ 5: ]
- return "%s%s" % ( base_url, url_for( controller = '/dataset', action = "display_application", dataset_id = self._dataset_hash, user_id = self._user_hash, app_name = self.parameter.link.display_application.id, link_name = self.parameter.link.id, app_action = self.action_name, action_param = self.parameter.url ) )
+ return "%s%s" % ( base_url, url_for( controller = '/dataset', action = "display_application", dataset_id = self._dataset_hash, user_id = self._user_hash, app_name = self.parameter.link.display_application.id, link_name = self.parameter.link.id, app_action = self.action_name, action_param = self._url ) )
@property
def action_name( self ):
return self.ACTION_NAME
@@ -178,9 +181,9 @@
if self.parameter.mime_type is not None:
return self.parameter.mime_type
if self.parameter.guess_mime_type:
- mime, encoding = mimetypes.guess_type( self.parameter.url )
+ mime, encoding = mimetypes.guess_type( self._url )
if not mime:
- mime = self.trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( self.parameter.url )[ -1 ], None )
+ mime = self.trans.app.datatypes_registry.get_mimetype_by_extension( ".".split( self._url )[ -1 ], None )
if mime:
return mime
return self.other_values[ DEFAULT_DATASET_NAME ].get_mime()
diff -r 262b16c8e277 -r f13d85256124 lib/galaxy/datatypes/registry.py
--- a/lib/galaxy/datatypes/registry.py Thu Mar 11 13:51:53 2010 -0500
+++ b/lib/galaxy/datatypes/registry.py Thu Mar 11 14:35:36 2010 -0500
@@ -25,6 +25,7 @@
self.sniff_order = []
self.upload_file_formats = []
self.display_applications = odict() #map a display application id to a display application
+ inherit_display_application_by_class = []
if root_dir and config:
# Parse datatypes_conf.xml
tree = galaxy.util.parse_xml( config )
@@ -42,11 +43,11 @@
for elem in registration.findall( 'datatype' ):
try:
extension = elem.get( 'extension', None )
- type = elem.get( 'type', None )
+ dtype = elem.get( 'type', None )
mimetype = elem.get( 'mimetype', None )
display_in_upload = elem.get( 'display_in_upload', False )
- if extension and type:
- fields = type.split( ':' )
+ if extension and dtype:
+ fields = dtype.split( ':' )
datatype_module = fields[0]
datatype_class = fields[1]
fields = datatype_module.split( '.' )
@@ -85,27 +86,36 @@
for display_app in elem.findall( 'display' ):
display_file = display_app.get( 'file', None )
assert display_file is not None, "A file must be specified for a datatype display tag."
+ inherit = galaxy.util.string_as_bool( display_app.get( 'inherit', 'False' ) )
display_app = DisplayApplication.from_file( os.path.join( self.display_applications_path, display_file ), self )
if display_app:
if display_app.id in self.display_applications:
#if we already loaded this display application, we'll use the first one again
display_app = self.display_applications[ display_app.id ]
- self.log.debug( "Loaded display application '%s' for datatype '%s'" % ( display_app.id, extension ) )
+ self.log.debug( "Loaded display application '%s' for datatype '%s', inherit=%s" % ( display_app.id, extension, inherit ) )
self.display_applications[ display_app.id ] = display_app #Display app by id
self.datatypes_by_extension[ extension ].add_display_application( display_app )
-
+ if inherit and ( self.datatypes_by_extension[extension], display_app ) not in inherit_display_application_by_class:
+ #subclass inheritance will need to wait until all datatypes have been loaded
+ inherit_display_application_by_class.append( ( self.datatypes_by_extension[extension], display_app ) )
except Exception, e:
self.log.warning( 'Error loading datatype "%s", problem: %s' % ( extension, str( e ) ) )
+ # Handle display_application subclass inheritance here:
+ for ext, d_type1 in self.datatypes_by_extension.iteritems():
+ for d_type2, display_app in inherit_display_application_by_class:
+ current_app = d_type1.get_display_application( display_app.id, None )
+ if current_app is None and isinstance( d_type1, type( d_type2 ) ):
+ d_type1.add_display_application( display_app )
# Load datatype sniffers from the config
sniff_order = []
sniffers = root.find( 'sniffers' )
for elem in sniffers.findall( 'sniffer' ):
- type = elem.get( 'type', None )
- if type:
- sniff_order.append( type )
- for type in sniff_order:
+ dtype = elem.get( 'type', None )
+ if dtype:
+ sniff_order.append( dtype )
+ for dtype in sniff_order:
try:
- fields = type.split( ":" )
+ fields = dtype.split( ":" )
datatype_module = fields[0]
datatype_class = fields[1]
fields = datatype_module.split( "." )
@@ -120,9 +130,9 @@
break
if not included:
self.sniff_order.append( aclass )
- self.log.debug( 'Loaded sniffer for datatype: %s' % type )
+ self.log.debug( 'Loaded sniffer for datatype: %s' % dtype )
except Exception, exc:
- self.log.warning( 'Error appending datatype %s to sniff_order, problem: %s' % ( type, str( exc ) ) )
+ self.log.warning( 'Error appending datatype %s to sniff_order, problem: %s' % ( dtype, str( exc ) ) )
#default values
if len(self.datatypes_by_extension) < 1:
self.datatypes_by_extension = {
diff -r 262b16c8e277 -r f13d85256124 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Thu Mar 11 13:51:53 2010 -0500
+++ b/lib/galaxy/model/__init__.py Thu Mar 11 14:35:36 2010 -0500
@@ -637,6 +637,9 @@
return ( None, None )
return get_source( self )
+ def get_display_applications( self, trans ):
+ return self.datatype.get_display_applications_by_dataset( self, trans )
+
class HistoryDatasetAssociation( DatasetInstance ):
def __init__( self,
hid = None,
diff -r 262b16c8e277 -r f13d85256124 templates/root/history_common.mako
--- a/templates/root/history_common.mako Thu Mar 11 13:51:53 2010 -0500
+++ b/templates/root/history_common.mako Thu Mar 11 14:35:36 2010 -0500
@@ -102,7 +102,7 @@
%endif
%endfor
%endif
- %for display_app in data.datatype.display_applications.itervalues():
+ %for display_app in data.get_display_applications( trans ).itervalues():
| ${display_app.name}
%for link_app in display_app.links.itervalues():
<a target="${link_app.url.get( 'target_frame', '_blank' )}" href="${link_app.get_display_url( data, trans )}">${_(link_app.name)}</a>
diff -r 262b16c8e277 -r f13d85256124 tool-data/shared/bx/bx_build_sites.txt
--- a/tool-data/shared/bx/bx_build_sites.txt Thu Mar 11 13:51:53 2010 -0500
+++ b/tool-data/shared/bx/bx_build_sites.txt Thu Mar 11 14:35:36 2010 -0500
@@ -1,1 +1,1 @@
-main http://main.genome-browser.bx.psu.edu/cgi-bin/hgTracks? hg18,hg19,mm8,mm9
+main http://main.genome-browser.bx.psu.edu/cgi-bin/hgTracks? hg18,hg19,mm8,mm9 bx-main
1
0