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
January 2010
- 29 participants
- 156 discussions
25 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/b4c62757393a
changeset: 3266:b4c62757393a
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Mon Jan 25 12:43:45 2010 -0500
description:
Better slug generation by ignoring non-alphanumeric characters.
diffstat:
lib/galaxy/web/base/controller.py | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diffs (19 lines):
diff -r 17db30ce0486 -r b4c62757393a lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Mon Jan 25 10:01:04 2010 -0500
+++ b/lib/galaxy/web/base/controller.py Mon Jan 25 12:43:45 2010 -0500
@@ -148,7 +148,15 @@
def set_item_slug( self, sa_session, item ):
""" Set item slug. Slug is unique among user's importable items for item's class. """
if item.slug is None or item.slug == "":
+ # Replace whitespace with '-'
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 '-'.
+ if slug_base.endswith('-'):
+ slug_base = slug_base[:-1]
+
+ # Make sure that slug is not taken; if it is, add a number to it.
slug = slug_base
count = 1
while sa_session.query( item.__class__ ).filter_by( user=item.user, slug=slug, importable=True ).count() != 0:
1
0
25 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/1dddb95579a1
changeset: 3265:1dddb95579a1
user: Nate Coraor <nate(a)bx.psu.edu>
date: Mon Jan 25 11:08:21 2010 -0500
description:
Fix library uploads when using the nginx upload module (redirect URL cannot include GET params)
diffstat:
lib/galaxy/tools/__init__.py | 9 +++++----
lib/galaxy/web/controllers/library.py | 3 +++
lib/galaxy/web/controllers/library_admin.py | 4 ++++
lib/galaxy/web/controllers/library_common.py | 9 ++++++++-
4 files changed, 20 insertions(+), 5 deletions(-)
diffs (67 lines):
diff -r 17db30ce0486 -r 1dddb95579a1 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Mon Jan 25 10:01:04 2010 -0500
+++ b/lib/galaxy/tools/__init__.py Mon Jan 25 11:08:21 2010 -0500
@@ -5,7 +5,7 @@
pkg_resources.require( "simplejson" )
-import logging, os, string, sys, tempfile, glob, shutil, types
+import logging, os, string, sys, tempfile, glob, shutil, types, urllib
import simplejson
import binascii
from UserDict import DictMixin
@@ -432,10 +432,11 @@
# Handle properties of the input form
self.check_values = util.string_as_bool( input_elem.get("check_values", "true") )
self.nginx_upload = util.string_as_bool( input_elem.get( "nginx_upload", "false" ) )
+ self.action = input_elem.get( 'action', '/tool_runner/index' )
if self.nginx_upload and self.app.config.nginx_upload_path:
- self.action = input_elem.get( "action", self.app.config.nginx_upload_path + "?nginx_redir=/tool_runner/index" )
- else:
- self.action = input_elem.get( "action", "/tool_runner/index")
+ if '?' in urllib.unquote_plus( self.action ):
+ raise Exception( 'URL parameters in a non-default tool action can not be used in conjunction with nginx upload. Please convert them to hidden POST parameters' )
+ self.action = self.app.config.nginx_upload_path + '?nginx_redir=' + urllib.unquote_plus( self.action )
self.target = input_elem.get( "target", "galaxy_main" )
self.method = input_elem.get( "method", "post" )
# Parse the actual parameters
diff -r 17db30ce0486 -r 1dddb95579a1 lib/galaxy/web/controllers/library.py
--- a/lib/galaxy/web/controllers/library.py Mon Jan 25 10:01:04 2010 -0500
+++ b/lib/galaxy/web/controllers/library.py Mon Jan 25 11:08:21 2010 -0500
@@ -34,3 +34,6 @@
default_action=params.get( 'default_action', None ),
msg=msg,
messagetype=messagetype )
+ @web.expose
+ def upload_library_dataset( self, trans, library_id, folder_id, **kwd ):
+ return trans.webapp.controllers[ 'library_common' ].upload_library_dataset( trans, 'library', library_id, folder_id, **kwd )
diff -r 17db30ce0486 -r 1dddb95579a1 lib/galaxy/web/controllers/library_admin.py
--- a/lib/galaxy/web/controllers/library_admin.py Mon Jan 25 10:01:04 2010 -0500
+++ b/lib/galaxy/web/controllers/library_admin.py Mon Jan 25 11:08:21 2010 -0500
@@ -239,3 +239,7 @@
id=library_id,
msg=msg,
messagetype=status ) )
+ @web.expose
+ @web.require_admin
+ def upload_library_dataset( self, trans, library_id, folder_id, **kwd ):
+ return trans.webapp.controllers[ 'library_common' ].upload_library_dataset( trans, 'library_admin', library_id, folder_id, **kwd )
diff -r 17db30ce0486 -r 1dddb95579a1 lib/galaxy/web/controllers/library_common.py
--- a/lib/galaxy/web/controllers/library_common.py Mon Jan 25 10:01:04 2010 -0500
+++ b/lib/galaxy/web/controllers/library_common.py Mon Jan 25 11:08:21 2010 -0500
@@ -701,7 +701,14 @@
# If we're using nginx upload, override the form action
action = web.url_for( controller='library_common', action='upload_library_dataset', cntrller=cntrller )
if upload_option == 'upload_file' and trans.app.config.nginx_upload_path:
- action = web.url_for( trans.app.config.nginx_upload_path ) + '?nginx_redir=' + action
+ # url_for is intentionally not used on the base URL here -
+ # nginx_upload_path is expected to include the proxy prefix if the
+ # administrator intends for it to be part of the URL. We also
+ # redirect to the library or library_admin controller rather than
+ # library_common because GET arguments can't be used in conjunction
+ # with nginx upload (nginx can't do percent decoding without a
+ # bunch of hacky rewrite rules).
+ action = trans.app.config.nginx_upload_path + '?nginx_redir=' + web.url_for( controller=cntrller, action='upload_library_dataset' )
return trans.fill_template( '/library/common/upload.mako',
cntrller=cntrller,
upload_option=upload_option,
1
0
25 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/17db30ce0486
changeset: 3264:17db30ce0486
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Mon Jan 25 10:01:04 2010 -0500
description:
Fix fast_compute_length performance by using version contributed by Bjoern Gruning, and fix email configuration bug in the user controller which was found by Ed Kirton.
diffstat:
lib/galaxy/web/controllers/user.py | 2 +-
tools/fasta_tools/fasta_compute_length.py | 41 +++++++++++++++---------------
2 files changed, 22 insertions(+), 21 deletions(-)
diffs (73 lines):
diff -r fe6e3c197d69 -r 17db30ce0486 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py Sun Jan 24 17:38:05 2010 -0500
+++ b/lib/galaxy/web/controllers/user.py Mon Jan 25 10:01:04 2010 -0500
@@ -593,7 +593,7 @@
for i in range(15):
new_pass = new_pass + choice(chars)
mail = os.popen("%s -t" % trans.app.config.sendmail_path, 'w')
- mail.write("To: %s\nFrom: no-reply@%s\nSubject: Galaxy Password Reset\n\nYour password has been reset to \"%s\" (no quotes)." % (email, trans.request.remote_addr, new_pass) )
+ mail.write("To: %s\nFrom: no-reply(a)nowhere.edu\nSubject: Galaxy Password Reset\n\nYour password has been reset to \"%s\" (no quotes)." % (email, new_pass) )
if mail.close():
return trans.show_error_message( 'Failed to reset password. If this problem persists, please submit a bug report.' )
reset_user.set_password_cleartext( new_pass )
diff -r fe6e3c197d69 -r 17db30ce0486 tools/fasta_tools/fasta_compute_length.py
--- a/tools/fasta_tools/fasta_compute_length.py Sun Jan 24 17:38:05 2010 -0500
+++ b/tools/fasta_tools/fasta_compute_length.py Mon Jan 25 10:01:04 2010 -0500
@@ -12,35 +12,36 @@
def __main__():
infile = sys.argv[1]
- outfile = sys.argv[2]
- keep_first = int( sys.argv[3] )
-
- fasta_title = fasta_seq = ''
+ out = open( sys.argv[2], 'w')
+ keep_first_char = int( sys.argv[3] )
+
+ fasta_title = ''
+ seq_len = 0
# number of char to keep in the title
- if keep_first == 0:
- keep_first = None
+ if keep_first_char == 0:
+ keep_first_char = None
else:
- keep_first += 1
+ keep_first_char += 1
- out = open(outfile, 'w')
-
- for i, line in enumerate( file( infile ) ):
- line = line.rstrip( '\r\n' )
+ first_entry = True
+
+ for line in open( infile ):
+ line = line.strip()
if not line or line.startswith( '#' ):
continue
if line[0] == '>':
- if len( fasta_seq ) > 0 :
- out.write( "%s\t%d\n" % ( fasta_title[ 1:keep_first ], len( fasta_seq ) ) )
+ if first_entry == False:
+ out.write( "%s\t%d\n" % ( fasta_title[ 1:keep_first_char ], seq_len ) )
+ else:
+ first_entry = False
fasta_title = line
- fasta_seq = ''
+ seq_len = 0
else:
- fasta_seq = "%s%s" % ( fasta_seq, line )
-
- # check the last sequence
- if len( fasta_seq ) > 0:
- out.write( "%s\t%d\n" % ( fasta_title[ 1:keep_first ], len( fasta_seq ) ) )
-
+ seq_len += len(line)
+
+ # last fasta-entry
+ out.write( "%s\t%d\n" % ( fasta_title[ 1:keep_first_char ], seq_len ) )
out.close()
if __name__ == "__main__" : __main__()
\ No newline at end of file
1
0
25 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/fe6e3c197d69
changeset: 3263:fe6e3c197d69
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Sun Jan 24 17:38:05 2010 -0500
description:
Added sharing options to pages and refactored sharing/display code to create a common code base. Also small additions to grid framework and bug fixes for pages.
diffstat:
lib/galaxy/model/__init__.py | 5 +
lib/galaxy/model/mapping.py | 11 +
lib/galaxy/model/migrate/versions/0034_page_user_share_association.py | 41 +
lib/galaxy/web/base/controller.py | 6 +-
lib/galaxy/web/controllers/history.py | 13 +-
lib/galaxy/web/controllers/page.py | 131 +++-
lib/galaxy/web/controllers/workflow.py | 5 +-
templates/base_panels.mako | 2 +-
templates/display_base.mako | 69 +-
templates/display_common.mako | 91 ++
templates/grid_base.mako | 77 +-
templates/grid_base_async.mako | 4 +-
templates/grid_common.mako | 8 +-
templates/history/view.mako | 2 +-
templates/page/display.mako | 5 -
templates/page/editor.mako | 8 +-
templates/page/index.mako | 33 +-
templates/page/select_histories_grid.mako | 4 +-
templates/share_base.mako | 36 +
templates/sharing_base.mako | 317 ++++-----
templates/workflow/display.mako | 2 +-
21 files changed, 552 insertions(+), 318 deletions(-)
diffs (1304 lines):
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/model/__init__.py Sun Jan 24 17:38:05 2010 -0500
@@ -1452,6 +1452,11 @@
self.user = None
self.title = None
self.content = None
+
+class PageUserShareAssociation( object ):
+ def __init__( self ):
+ self.page = None
+ self.user = None
class Visualization( object ):
def __init__( self ):
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/model/mapping.py Sun Jan 24 17:38:05 2010 -0500
@@ -683,6 +683,12 @@
Column( "content", TEXT )
)
+PageUserShareAssociation.table = Table( "page_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "page_id", Integer, ForeignKey( "page.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
+
Visualization.table = Table( "visualization", metadata,
Column( "id", Integer, primary_key=True ),
Column( "create_time", DateTime, default=now ),
@@ -1236,6 +1242,11 @@
lazy=False ),
tags=relation(PageTagAssociation, order_by=PageTagAssociation.table.c.id, backref="pages")
) )
+
+assign_mapper( context, PageUserShareAssociation, PageUserShareAssociation.table,
+ properties=dict( user=relation( User, backref='pages_shared_by_others' ),
+ page=relation( Page, backref='users_shared_with' )
+ ) )
assign_mapper( context, VisualizationRevision, VisualizationRevision.table )
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/model/migrate/versions/0034_page_user_share_association.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0034_page_user_share_association.py Sun Jan 24 17:38:05 2010 -0500
@@ -0,0 +1,41 @@
+"""
+Migration script to create a table for page-user share association.
+"""
+
+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 ) )
+
+PageUserShareAssociation_table = Table( "page_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "page_id", Integer, ForeignKey( "page.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create stored_workflow_tag_association table.
+ try:
+ PageUserShareAssociation_table.create()
+ except Exception, e:
+ print str(e)
+ log.debug( "Creating page_user_share_association table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop workflow_tag_association table.
+ try:
+ PageUserShareAssociation_table.drop()
+ except Exception, e:
+ print str(e)
+ log.debug( "Dropping page_user_share_association table failed: %s" % str( e ) )
\ No newline at end of file
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/web/base/controller.py Sun Jan 24 17:38:05 2010 -0500
@@ -143,9 +143,11 @@
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 )
- # Set item slug. Slug must be unique among user's importable items for item's class.
- if item.slug is None:
+ def set_item_slug( self, sa_session, item ):
+ """ Set item slug. Slug is unique among user's importable items for item's class. """
+ if item.slug is None or item.slug == "":
slug_base = re.sub( "\s+", "-", item.name.lower() )
slug = slug_base
count = 1
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/web/controllers/history.py Sun Jan 24 17:38:05 2010 -0500
@@ -225,7 +225,7 @@
elif operation == "enable import via link":
for history in histories:
if not history.importable:
- self.make_item_importable( trans.sa_session, history )
+ self._make_item_importable( trans.sa_session, history )
elif operation == "disable import via link":
if history_ids:
histories = [ self.get_history( trans, history_id ) for history_id in history_ids ]
@@ -380,16 +380,16 @@
return
@web.expose
- @web.require_login( "set history's importable flag" )
- def set_importable_async( self, trans, id=None, importable=False ):
+ @web.require_login( "set history's accessible flag" )
+ def set_accessible_async( self, trans, id=None, accessible=False ):
""" Set history's importable attribute and sets history's slug. """
history = self.get_history( trans, id, True )
# Only set if importable value would change; this prevents a change in the update_time unless attribute really changed.
- importable = importable in ['True', 'true', 't', 'T'];
+ importable = accessible in ['True', 'true', 't', 'T'];
if history and history.importable != importable:
if importable:
- self.make_item_importable( trans.sa_session, history )
+ self._make_item_accessible( trans.sa_session, history )
else:
history.importable = importable
trans.sa_session.flush()
@@ -588,7 +588,7 @@
for history in histories:
trans.sa_session.add( history )
if params.get( 'enable_import_via_link', False ):
- self.make_item_importable( trans.sa_session, history )
+ self._make_item_accessible( trans.sa_session, history )
trans.sa_session.flush()
elif params.get( 'disable_import_via_link', False ):
history.importable = False
@@ -893,6 +893,7 @@
share.history = history
share.user = send_to_user
trans.sa_session.add( share )
+ self.set_item_slug( trans.sa_session, history )
trans.sa_session.flush()
if history not in shared_histories:
shared_histories.append( history )
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/web/controllers/page.py
--- a/lib/galaxy/web/controllers/page.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/web/controllers/page.py Sun Jan 24 17:38:05 2010 -0500
@@ -29,7 +29,7 @@
grids.TextColumn( "Title", key="title", model_class=model.Page, attach_popup=True, filterable="advanced" ),
URLColumn( "Public URL" ),
grids.IndividualTagsColumn( "Tags", "tags", model.Page, model.PageTagAssociation, filterable="advanced", grid_name="PageListGrid" ),
- grids.GridColumn( "Published", key="published", format=format_bool, filterable="advanced" ),
+ SharingStatusColumn( "Sharing", key="sharing", model_class=model.History, filterable="advanced", sortable=False ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
]
@@ -46,9 +46,8 @@
grids.GridOperation( "View", allow_multiple=False, url_args=dict( action='display') ),
grids.GridOperation( "Edit name/id", 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" ),
- grids.GridOperation( "Publish", condition=( lambda item: not item.published ) ),
- grids.GridOperation( "Unpublish", condition=( lambda item: item.published ) ),
]
def apply_default_filter( self, trans, query, **kwargs ):
return query.filter_by( user=trans.user, deleted=False )
@@ -149,7 +148,7 @@
def apply_default_filter( self, trans, query, **kwargs ):
return query.filter_by( user=trans.user, purged=False )
-class PageController( BaseController ):
+class PageController( BaseController, Sharable ):
_page_list = PageListGrid()
_all_published_list = PageAllPublishedGrid()
@@ -157,7 +156,8 @@
@web.expose
@web.require_login()
- def index( self, trans, *args, **kwargs ):
+ def list( self, trans, *args, **kwargs ):
+ """ List user's pages. """
# Handle operation
if 'operation' in kwargs and 'id' in kwargs:
session = trans.sa_session
@@ -167,15 +167,24 @@
item = session.query( model.Page ).get( trans.security.decode_id( id ) )
if operation == "delete":
item.deleted = True
- elif operation == "publish":
- item.published = True
- elif operation == "unpublish":
- item.published = False
+ if operation == "share or publish":
+ return self.sharing( trans, **kwargs )
session.flush()
+
# Build grid
grid = self._page_list( trans, *args, **kwargs )
+
+ # Build list of pages shared with user.
+ shared_by_others = trans.sa_session \
+ .query( model.PageUserShareAssociation ) \
+ .filter_by( user=trans.get_user() ) \
+ .join( model.Page.table ) \
+ .filter( model.Page.deleted == False ) \
+ .order_by( desc( model.Page.update_time ) ) \
+ .all()
+
# Render grid wrapped in panels
- return trans.fill_template( "page/index.mako", grid=grid )
+ return trans.fill_template( "page/index.mako", grid=grid, shared_by_others=shared_by_others )
@web.expose
def list_published( self, trans, *args, **kwargs ):
@@ -222,7 +231,7 @@
session.flush()
# Display the management page
## trans.set_message( "Page '%s' created" % page.title )
- return trans.response.send_redirect( web.url_for( action='index' ) )
+ return trans.response.send_redirect( web.url_for( action='list' ) )
return trans.show_form(
web.FormBuilder( web.url_for(), "Create new page", submit_text="Submit" )
.add_text( "page_title", "Page title", value=page_title, error=page_title_err )
@@ -288,6 +297,78 @@
return trans.fill_template( "page/editor.mako", page=page )
@web.expose
+ @web.require_login( "use Galaxy pages" )
+ def sharing( self, trans, id, **kwargs ):
+ """ Handle page sharing. """
+
+ # Get session and page.
+ session = trans.sa_session
+ page = trans.sa_session.query( model.Page ).get( trans.security.decode_id( id ) )
+
+ # Do operation on page.
+ if 'make_accessible_via_link' in kwargs:
+ self._make_item_accessible( trans.sa_session, page )
+ elif 'make_accessible_and_publish' in kwargs:
+ self._make_item_accessible( trans.sa_session, page )
+ page.published = True
+ elif 'publish' in kwargs:
+ page.published = True
+ elif 'disable_link_access' in kwargs:
+ page.importable = False
+ elif 'unpublish' in kwargs:
+ page.published = False
+ elif 'disable_link_access_and_unpubish' in kwargs:
+ page.importable = page.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.PageUserShareAssociation ) \
+ .filter_by( user=user, page=page ).one()
+ session.delete( association )
+
+ session.flush()
+
+ return trans.fill_template( "/sharing_base.mako",
+ item=page )
+
+ @web.expose
+ @web.require_login( "use Galaxy pages" )
+ def share( self, trans, id, email="" ):
+ msg = mtype = None
+ page = trans.sa_session.query( model.Page ).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 workflow 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 )
+ else:
+ share = model.PageUserShareAssociation()
+ share.page = page
+ share.user = other
+ session = trans.sa_session
+ session.add( share )
+ self.set_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 ) )
+ return trans.fill_template( "/share_base.mako",
+ message = msg,
+ messagetype = mtype,
+ item=page,
+ email=email )
+
+ @web.expose
@web.require_login()
def save( self, trans, id, content ):
id = trans.security.decode_id( id )
@@ -308,20 +389,30 @@
def display( self, trans, id ):
id = trans.security.decode_id( id )
page = trans.sa_session.query( model.Page ).get( id )
- if page.user is not trans.user:
- error( "Page is not owned by current user" )
- return trans.fill_template( "page/display.mako", page=page )
-
+ if not page:
+ raise web.httpexceptions.HTTPNotFound()
+ return self.display_by_username_and_slug( trans, page.user.username, page.slug )
+
@web.expose
def display_by_username_and_slug( self, trans, username, slug ):
+ """ Display page based on a username and slug. """
+ session = trans.sa_session
+
+ # Get page.
session = trans.sa_session
user = session.query( model.User ).filter_by( username=username ).first()
- if user is None:
- raise web.httpexceptions.HTTPNotFound()
- page = trans.sa_session.query( model.Page ).filter_by( user=user, slug=slug, deleted=False, published=True ).first()
+ page_query_base = trans.sa_session.query( model.Page ).filter_by( user=user, slug=slug, deleted=False )
+ if user is not None:
+ # User can view page if it's importable or if it's shared with him/her.
+ page = page_query_base.filter( or_( model.Page.user==trans.get_user(), model.Page.importable==True, model.Page.users_shared_with.any( model.PageUserShareAssociation.user==trans.get_user() ) ) ).first()
+ else:
+ # User not logged in, so only way to view page is if it's importable.
+ page = page_query_base.filter_by( importable=True ).first()
if page is None:
- raise web.httpexceptions.HTTPNotFound()
- return trans.fill_template( "page/display.mako", item=page )
+ raise web.httpexceptions.HTTPNotFound()
+
+ return trans.fill_template_mako( "page/display.mako", item=page)
+
@web.expose
@web.require_login("select a history from saved histories")
diff -r a72dc4023e59 -r fe6e3c197d69 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Sat Jan 23 15:52:42 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Sun Jan 24 17:38:05 2010 -0500
@@ -155,10 +155,10 @@
@web.expose
def display_by_username_and_slug( self, trans, username, slug ):
- """ View workflow based on a username and slug. """
+ """ Display workflow based on a username and slug. """
session = trans.sa_session
- # Get history.
+ # Get workflow.
session = trans.sa_session
user = session.query( model.User ).filter_by( username=username ).first()
workflow_query_base = trans.sa_session.query( model.StoredWorkflow ).filter_by( user=user, slug=slug, deleted=False )
@@ -221,6 +221,7 @@
share.user = other
session = trans.sa_session
session.add( share )
+ self.set_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 ) )
diff -r a72dc4023e59 -r fe6e3c197d69 templates/base_panels.mako
--- a/templates/base_panels.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/base_panels.mako Sun Jan 24 17:38:05 2010 -0500
@@ -265,7 +265,7 @@
<li><a target="galaxy_main" href="${h.url_for( controller='/history', action='list' )}">Histories</a></li>
<li><a target="galaxy_main" href="${h.url_for( controller='/dataset', action='list' )}">Datasets</a></li>
%if app.config.get_bool( 'enable_pages', False ):
- <li><a href="${h.url_for( controller='/page' )}">Pages</a></li>
+ <li><a href="${h.url_for( controller='/page', action='list' )}">Pages</a></li>
%endif
%endif
</ul>
diff -r a72dc4023e59 -r fe6e3c197d69 templates/display_base.mako
--- a/templates/display_base.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/display_base.mako Sun Jan 24 17:38:05 2010 -0500
@@ -7,26 +7,16 @@
from galaxy import model
%>
<%inherit file="${inherit( context )}"/>
-<%namespace file="./tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
+<%namespace file="/tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
+<%namespace file="/display_common.mako" import="*" />
<%!
from galaxy.model import History, StoredWorkflow, Page
from galaxy.web.framework.helpers import iff
%>
-## Get display name for a class.
-<%def name="get_class_display_name( a_class )">
-<%
- ## Start with exceptions, end with default.
- if a_class is model.StoredWorkflow:
- return "Workflow"
- else:
- return a_class.__name__
-%>
-</%def>
-
<%def name="title()">
- Galaxy | ${iff( item.published, "Published ", iff( item.importable , "Accessible ", "Shared " ) ) + self.get_class_display_name( item.__class__ )} | ${item.name}
+ Galaxy | ${iff( item.published, "Published ", iff( item.importable , "Accessible ", iff( item.users_shared_with, "Shared ", "Private " ) ) ) + get_class_display_name( item.__class__ )} | ${get_item_name( item )}
</%def>
<%def name="init()">
@@ -88,10 +78,6 @@
Item
</%def>
-<%def name="get_item_name( item )">
- <% return item.name %>
-</%def>
-
##
## When page has no panels, center panel is body.
##
@@ -120,12 +106,13 @@
<a href="${href_to_all_items}">Published ${item_plural}</a> |
<a href="${href_to_user_items}">${item.user.username}</a>
%elif item.importable:
- Accessible ${self.get_class_display_name( item.__class__ )}
+ Accessible ${get_class_display_name( item.__class__ )}
+ %elif item.users_shared_with:
+ Shared ${get_class_display_name( item.__class__ )}
%else:
- ## Item shared with user.
- Shared ${self.get_class_display_name( item.__class__ )}
+ Private ${get_class_display_name( item.__class__ )}
%endif
- | ${self.get_item_name( item )}
+ | ${get_item_name( item )}
</div>
</div>
@@ -168,44 +155,4 @@
%endif
</div>
</div>
-</%def>
-
-
-##
-## Utility methods.
-##
-
-## Get plural term for item.
-<%def name="get_item_plural( item )">
- <%
- items_plural = "items"
- if isinstance( item, History ):
- items_plural = "Histories"
- elif isinstance( item, StoredWorkflow ):
- items_plural = "Workflows"
- elif isinstance( item, Page ):
- items_plural = "Pages"
- return items_plural
- %>
-</%def>
-
-## Returns the controller name for an item based on its class.
-<%def name="get_controller_name( item )">
- <%
- if isinstance( item, History ):
- return "history"
- elif isinstance( item, StoredWorkflow ):
- return "workflow"
- elif isinstance( item, Page ):
- return "page"
- %>
-</%def>
-
-## Return a link to view a history.
-<%def name="get_history_link( history, qualify=False )">
- %if history.slug and history.user.username:
- <% return h.url_for( controller='/history', action='display_by_username_and_slug', username=history.user.username, slug=history.slug, qualified=qualify ) %>
- %else:
- <% return h.url_for( controller='/history', action='view', id=trans.security.encode_id( history.id ), qualified=qualify ) %>
- %endif
</%def>
\ No newline at end of file
diff -r a72dc4023e59 -r fe6e3c197d69 templates/display_common.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/display_common.mako Sun Jan 24 17:38:05 2010 -0500
@@ -0,0 +1,91 @@
+##
+## Utilities for sharing items and displaying shared items.
+##
+<%! from galaxy import model %>
+
+## Get display name for a class.
+<%def name="get_class_display_name( a_class )">
+<%
+ ## Start with exceptions, end with default.
+ if a_class is model.StoredWorkflow:
+ return "Workflow"
+ else:
+ return a_class.__name__
+%>
+</%def>
+
+<%def name="get_item_name( item )">
+ <%
+ if type( item ) is model.Page:
+ return item.title
+ return item.name
+ %>
+</%def>
+
+## Get plural display name for a class.
+<%def name="get_class_plural_display_name( a_class )">
+<%
+ ## Start with exceptions, end with default.
+ if a_class is model.History:
+ return "Histories"
+ else:
+ return get_class_display_name( a_class ) + "s"
+%>
+</%def>
+
+## Get display name for a class.
+<%def name="get_class_display_name( a_class )">
+<%
+ ## Start with exceptions, end with default.
+ if a_class is model.StoredWorkflow:
+ return "Workflow"
+ else:
+ return a_class.__name__
+%>
+</%def>
+
+## Get plural term for item.
+<%def name="get_item_plural( item )">
+ <% return get_class_plural( item.__class__ ) %>
+</%def>
+
+## Get plural term for class.
+<%def name="get_class_plural( a_class )">
+ <%
+ if a_class == model.History:
+ class_plural = "Histories"
+ elif a_class == model.StoredWorkflow:
+ class_plural = "Workflows"
+ elif a_class == model.Page:
+ class_plural = "Pages"
+ elif a_class == model.Library:
+ class_plural = "Libraries"
+ elif a_class == model.HistoryDatasetAssociation:
+ class_plural = "Datasets"
+ else:
+ class_plural = a_class.__name__ + "s"
+ return class_plural
+ %>
+</%def>
+
+## Returns the controller name for an item based on its class.
+<%def name="get_controller_name( item )">
+ <%
+ if isinstance( item, model.History ):
+ return "history"
+ elif isinstance( item, model.StoredWorkflow ):
+ return "workflow"
+ elif isinstance( item, model.Page ):
+ return "page"
+ %>
+</%def>
+
+## Return a link to view a history.
+<%def name="get_history_link( history, qualify=False )">
+ %if history.slug and history.user.username:
+ <% return h.url_for( controller='/history', action='display_by_username_and_slug', username=history.user.username, slug=history.slug, qualified=qualify ) %>
+ %else:
+ <% return h.url_for( controller='/history', action='view', id=trans.security.encode_id( history.id ), qualified=qualify ) %>
+ %endif
+</%def>
+
diff -r a72dc4023e59 -r fe6e3c197d69 templates/grid_base.mako
--- a/templates/grid_base.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/grid_base.mako Sun Jan 24 17:38:05 2010 -0500
@@ -10,19 +10,18 @@
%>
<%inherit file="${inherit(context)}"/>
+##
+## Override methods from base.mako and base_panels.mako
+##
+
+<%def name="center_panel()">
+ ${make_grid( grid )}
+</%def>
+
## Render the grid's basic elements. Each of these elements can be subclassed.
-<table>
- <tr>
- <td width="75%">${self.render_grid_header()}</td>
- <td></td>
- <td width="25%" id="grid-message" valign="top">${self.render_grid_message()}</td>
- </tr>
-</table>
-
-${self.render_grid_table()}
-
-
-## Function definitions.
+<%def name="body()">
+ ${make_grid( grid )}
+</%def>
<%def name="title()">${grid.title}</%def>
@@ -711,10 +710,26 @@
</style>
</%def>
+##
+## Custom grid methods.
+##
+
<%namespace file="./grid_common.mako" import="*" />
+<%def name="make_grid( grid )">
+ <table>
+ <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>
+ </tr>
+ </table>
+
+ ${self.render_grid_table( grid )}
+</%def>
+
## Render grid message.
-<%def name="render_grid_message()">
+<%def name="render_grid_message( grid )">
%if message:
<p>
<div class="${message_type}message transient-message">${util.restore_text( message )}</div>
@@ -724,7 +739,7 @@
</%def>
## Render grid header.
-<%def name="render_grid_header(render_title=True)">
+<%def name="render_grid_header( grid, render_title=True)">
<div class="grid-header">
%if render_title:
<h2>${grid.title}</h2>
@@ -740,12 +755,12 @@
</ul>
%endif
- ${render_grid_filters()}
+ ${render_grid_filters( grid )}
</div>
</%def>
## Render grid.
-<%def name="render_grid_table(show_item_checkboxes=False)">
+<%def name="render_grid_table( grid, show_item_checkboxes=False)">
<%
# Set flag to indicate whether grid has operations that operate on multiple items.
multiple_item_ops_exist = False
@@ -801,17 +816,17 @@
</tr>
</thead>
<tbody id="grid-table-body">
- ${render_grid_table_body_contents(show_item_checkboxes)}
+ ${render_grid_table_body_contents( grid, show_item_checkboxes )}
</tbody>
<tfoot>
- ${render_grid_table_footer_contents(show_item_checkboxes)}
+ ${render_grid_table_footer_contents( grid, show_item_checkboxes )}
</tfoot>
</table>
</form>
</%def>
## Render grid table body contents.
-<%def name="render_grid_table_body_contents(show_item_checkboxes=False)">
+<%def name="render_grid_table_body_contents(grid, show_item_checkboxes=False)">
<% num_rows_rendered = 0 %>
%if query.count() == 0:
## No results.
@@ -901,27 +916,15 @@
</%def>
## Render grid table footer contents.
-<%def name="render_grid_table_footer_contents(show_item_checkboxes=False)">
+<%def name="render_grid_table_footer_contents(grid, show_item_checkboxes=False)">
## Row for navigating among pages.
- <%
- # Mapping between item class and plural term for item.
- items_plural = "items"
- if grid.model_class == History:
- items_plural = "histories"
- elif grid.model_class == HistoryDatasetAssociation:
- items_plural = "datasets"
- elif grid.model_class == User:
- items_plural = "users"
- elif grid.model_class == Role:
- items_plural = "roles"
- elif grid.model_class == Group:
- items_plural = "groups"
- %>
- %if show_item_checkboxes:
- <td></td>
- %endif
+ <%namespace file="/display_common.mako" import="get_class_plural" />
+ <% items_plural = get_class_plural( grid.model_class ).lower() %>
%if grid.use_paging and num_pages > 1:
<tr id="page-links-row">
+ %if show_item_checkboxes:
+ <td></td>
+ %endif
<td colspan="100">
<span id='page-link-container'>
## Page links.
diff -r a72dc4023e59 -r fe6e3c197d69 templates/grid_base_async.mako
--- a/templates/grid_base_async.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/grid_base_async.mako Sun Jan 24 17:38:05 2010 -0500
@@ -8,8 +8,8 @@
multiple_item_ops_exist = True
%>
-${render_grid_table_body_contents(show_item_checkboxes=multiple_item_ops_exist)}
+${render_grid_table_body_contents( grid, show_item_checkboxes=multiple_item_ops_exist )}
*****
${num_pages}
*****
-${render_grid_message()}
\ No newline at end of file
+${render_grid_message( grid )}
\ No newline at end of file
diff -r a72dc4023e59 -r fe6e3c197d69 templates/grid_common.mako
--- a/templates/grid_common.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/grid_common.mako Sun Jan 24 17:38:05 2010 -0500
@@ -4,7 +4,7 @@
%>
## Render a filter UI for a grid column. Filter is rendered as a table row.
-<%def name="render_grid_column_filter(column)">
+<%def name="render_grid_column_filter( grid, column )">
<tr>
<%
column_label = column.label
@@ -95,7 +95,7 @@
</%def>
## Print grid search/filtering UI.
-<%def name="render_grid_filters()">
+<%def name="render_grid_filters( grid )">
## Standard search.
<div>
<table><tr>
@@ -103,7 +103,7 @@
<table>
%for column in grid.columns:
%if column.filterable == "standard":
- ${render_grid_column_filter(column)}
+ ${render_grid_column_filter( grid, column )}
%endif
%endfor
</table>
@@ -168,7 +168,7 @@
</script>
%endif
- ${render_grid_column_filter(column)}
+ ${render_grid_column_filter( grid, column )}
%endif
%endfor
</table>
diff -r a72dc4023e59 -r fe6e3c197d69 templates/history/view.mako
--- a/templates/history/view.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/history/view.mako Sun Jan 24 17:38:05 2010 -0500
@@ -1,5 +1,5 @@
<%inherit file="/base_panels.mako"/>
-<%namespace file="/display_base.mako" import="get_history_link, get_controller_name" />
+<%namespace file="/display_common.mako" import="get_history_link, get_controller_name" />
<%namespace file="/root/history_common.mako" import="render_dataset" />
<%namespace file="/tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
diff -r a72dc4023e59 -r fe6e3c197d69 templates/page/display.mako
--- a/templates/page/display.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/page/display.mako Sun Jan 24 17:38:05 2010 -0500
@@ -1,10 +1,5 @@
<%inherit file="/display_base.mako"/>
-<%def name="title()">
- <% page = item %>
- Galaxy :: ${page.user.username} :: ${page.title}
-</%def>
-
<%def name="javascripts()">
${parent.javascripts()}
${h.js( "jquery", "json2", "jquery.jstore-all", "jquery.autocomplete", "autocomplete_tagging" )}
diff -r a72dc4023e59 -r fe6e3c197d69 templates/page/editor.mako
--- a/templates/page/editor.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/page/editor.mako Sun Jan 24 17:38:05 2010 -0500
@@ -212,7 +212,7 @@
"Insert Link to History",
table_html +
"<div><input id='make-importable' type='checkbox' checked/>" +
- "Publish the selected histories so that they can viewed by everyone.</div>"
+ "Make the selected histories accessible so that they can viewed by everyone.</div>"
,
{
"Insert": function()
@@ -231,8 +231,8 @@
if (make_importable)
$.ajax({
type: "POST",
- url: '${h.url_for( controller='history', action='set_importable_async' )}',
- data: { id: item_id, importable: 'True' },
+ url: '${h.url_for( controller='history', action='set_accessible_async' )}',
+ data: { id: item_id, accessible: 'True' },
error: function() { alert('Make history importable failed; id=' + item_id) }
});
@@ -412,7 +412,7 @@
});
## Close button
$("#close-button").click(function() {
- <% next_url = h.url_for( controller='page', action='index' ) %>
+ <% next_url = h.url_for( controller='page', action='list' ) %>
// var new_content = editor.xhtml();
// var changed = ( initial_content != new_content );
var changed = false;
diff -r a72dc4023e59 -r fe6e3c197d69 templates/page/index.mako
--- a/templates/page/index.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/page/index.mako Sun Jan 24 17:38:05 2010 -0500
@@ -16,8 +16,39 @@
<div style="overflow: auto; height: 100%;">
<div class="page-container" style="padding: 10px;">
${grid}
+
+ <br><br>
+ <h2>Pages 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 ):
+ <% page = association.page %>
+ <tr>
+ <td>
+ <a class="menubutton" id="shared-${i}-popup" href="${h.url_for( action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}">${page.title}</a>
+ </td>
+ <td>${page.user.username}</td>
+ <td>
+ <div popupmenu="shared-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='display_by_username_and_slug', username=page.user.username, slug=page.slug)}" target="_top">View</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
+
+ No pages have been shared with you.
+
+ %endif
+
</div>
</div>
-
</%def>
diff -r a72dc4023e59 -r fe6e3c197d69 templates/page/select_histories_grid.mako
--- a/templates/page/select_histories_grid.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/page/select_histories_grid.mako Sun Jan 24 17:38:05 2010 -0500
@@ -3,8 +3,8 @@
${javascripts()}
${stylesheets()}
-${render_grid_header(False)}
-${render_grid_table(show_item_checkboxes=True)}
+${render_grid_header( grid, False )}
+${render_grid_table( grid, show_item_checkboxes=True )}
## Initialize the grid.
<script type="text/javascript">
diff -r a72dc4023e59 -r fe6e3c197d69 templates/share_base.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/share_base.mako Sun Jan 24 17:38:05 2010 -0500
@@ -0,0 +1,36 @@
+<%inherit file="/base.mako"/>
+
+%if message:
+<%
+if messagetype is UNDEFINED:
+ mt = "done"
+else:
+ mt = messagetype
+%>
+<p />
+<div class="${mt}message">
+ ${message}
+</div>
+<p />
+%endif
+
+<div class="toolForm">
+ <div class="toolFormTitle">Share page '${item.title}'</div>
+ <div class="toolFormBody">
+ <form action="${h.url_for( action='share', id=trans.security.encode_id( item.id ) )}" method="POST">
+ <div class="form-row">
+ <label>
+ Email address of user to share with
+ </label>
+ <div style="float: left; width: 250px; margin-right: 10px;">
+ <input type="text" name="email" value="${email}" size="40">
+ </div>
+ <div style="clear: both"></div>
+ </div>
+ <div class="form-row">
+ <input type="submit" value="Share"></input>
+ </div>
+ </form>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff -r a72dc4023e59 -r fe6e3c197d69 templates/sharing_base.mako
--- a/templates/sharing_base.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/sharing_base.mako Sun Jan 24 17:38:05 2010 -0500
@@ -4,14 +4,15 @@
##
<%inherit file="/base.mako"/>
-<%! from galaxy import model %>
+
+<%namespace file="./display_common.mako" import="*" />
##
## Page methods.
##
<%def name="title()">
- Sharing and Publishing ${get_class_display_name( item.__class__ )} '${item.name}'
+ Sharing and Publishing ${get_class_display_name( item.__class__ )} '${get_item_name( item )}'
</%def>
<%def name="stylesheets()">
@@ -28,177 +29,155 @@
</style>
</%def>
-## Get display name for a class.
-<%def name="get_class_display_name( a_class )">
-<%
- ## Start with exceptions, end with default.
- if a_class is model.StoredWorkflow:
- return "Workflow"
- else:
- return a_class.__name__
-%>
-</%def>
+<%def name="body()">
+ <%
+ #
+ # Setup and variables needed for page.
+ #
+
+ # Get class name strings.
+ item_class_name = get_class_display_name( item.__class__ )
+ item_class_name_lc = item_class_name.lower()
+ item_class_plural_name = get_class_plural_display_name( item.__class__ )
+ item_class_plural_name_lc = item_class_plural_name.lower()
+ %>
+ <% item_name = get_item_name(item) %>
-## Get plural display name for a class.
-<%def name="get_class_plural_display_name( a_class )">
-<%
- ## Start with exceptions, end with default.
- if a_class is model.History:
- return "Histories"
- else:
- return get_class_display_name( a_class ) + "s"
-%>
-</%def>
+ <h2>Sharing and Publishing ${item_class_name} '${item_name}'</h2>
-##
-## Page content.
-##
-<%
- #
- # Setup and variables needed for page.
- #
+ ## Require that user have a public username before sharing or publishing an item.
+ %if trans.get_user().username is None or trans.get_user().username is "":
+ To make a ${item_class_name_lc} accessible via link or publish it, you must create a public username:
+ <p>
+ <form action="${h.url_for( action='set_public_username', id=trans.security.encode_id( item.id ) )}"
+ method="POST">
+ <div class="form-row">
+ <label>Public Username:</label>
+ <div class="form-row-input">
+ <input type="text" name="username" size="40"/>
+ </div>
+ </div>
+ <div style="clear: both"></div>
+ <div class="form-row">
+ <input class="action-button" type="submit" name="Set Username" value="Set Username"/>
+ </div>
+ </form>
+ %else:
+ ## User has a public username, so private sharing and publishing options.
+ <div class="indent" style="margin-top: 2em">
+ <h3>Making ${item_class_name} Accessible via Link and Publishing It</h3>
- # Get class name strings.
- item_class_name = get_class_display_name( item.__class__ )
- item_class_name_lc = item_class_name.lower()
- item_class_plural_name = get_class_plural_display_name( item.__class__ )
- item_class_plural_name_lc = item_class_plural_name.lower()
-%>
+ <div class="indent">
+ %if item.importable:
+ <%
+ item_status = "accessible via link"
+ if item.published:
+ item_status = item_status + " and published"
+ %>
+ This ${item_class_name_lc} <strong>${item_status}</strong>.
+ <div class="indent">
+ <p>Anyone can view and import this ${item_class_name_lc} by visiting the following URL:
+ <% url = h.url_for( action='display_by_username_and_slug', username=trans.get_user().username, slug=item.slug, qualified=True ) %>
+ <blockquote>
+ <a href="${url}" target="_top">${url}</a>
+ </blockquote>
+
+ %if item.published:
+ This ${item_class_name_lc} is publicly listed and searchable in Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section.
+ %endif
+ </div>
+
+ <p>You can:
+ <div class="indent">
+ <form action="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ) )}"
+ method="POST">
+ %if not item.published:
+ ## Item is importable but not published. User can disable importable or publish.
+ <input class="action-button" type="submit" name="disable_link_access" value="Disable Access to ${item_class_name} Link">
+ <div class="toolParamHelp">Disables ${item_class_name_lc}'s link so that it is not accessible.</div>
+ <br>
+ <input class="action-button" type="submit" name="publish" value="Publish ${item_class_name}" method="POST">
+ <div class="toolParamHelp">Publishes the ${item_class_name_lc} to Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section, where it is publicly listed and searchable.</div>
-<h2>Sharing and Publishing ${item_class_name} '${item.name}'</h2>
+ <br>
+ %else: ## item.published == True
+ ## Item is importable and published. User can unpublish or disable import and unpublish.
+ <input class="action-button" type="submit" name="unpublish" value="Unpublish ${item_class_name}">
+ <div class="toolParamHelp">Removes ${item_class_name_lc} from Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section so that it is not publicly listed or searchable.</div>
+ <br>
+ <input class="action-button" type="submit" name="disable_link_access_and_unpubish" value="Disable Access to ${item_class_name} via Link and Unpublish">
+ <div class="toolParamHelp">Disables ${item_class_name_lc}'s link so that it is not accessible and removes ${item_class_name_lc} from Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section so that it is not publicly listed or searchable.</div>
+ %endif
+
+ </form>
+ </div>
+
+ %else:
+
+ This ${item_class_name_lc} is currently restricted so that only you and the users listed below can access it. You can:
+ <p>
+ <form action="${h.url_for( action='sharing', id=trans.security.encode_id(item.id) )}" method="POST">
+ <input class="action-button" type="submit" name="make_accessible_via_link" value="Make ${item_class_name} Accessible via Link">
+ <div class="toolParamHelp">Generates a web link that you can share with other people so that they can view and import the ${item_class_name_lc}.</div>
+
+ <br>
+ <input class="action-button" type="submit" name="make_accessible_and_publish" value="Make ${item_class_name} Accessible and Publish" method="POST">
+ <div class="toolParamHelp">Makes the ${item_class_name_lc} accessible via link (see above) and publishes the ${item_class_name_lc} to Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section, where it is publicly listed and searchable.</div>
+ </form>
+
+ %endif
+ </div>
-## Require that user have a public username before sharing or publishing an item.
-%if trans.get_user().username is None or trans.get_user().username is "":
- To make a ${item_class_name_lc} accessible via link or publish it, you must create a public username:
- <p>
- <form action="${h.url_for( action='set_public_username', id=trans.security.encode_id( item.id ) )}"
- method="POST">
- <div class="form-row">
- <label>Public Username:</label>
- <div class="form-row-input">
- <input type="text" name="username" size="40"/>
- </div>
+ <h3>Sharing ${item_class_name} with Specific Users</h3>
+
+ <div class="indent">
+ %if item.users_shared_with:
+
+ <p>
+ The following users will see this ${item_class_name_lc} in their ${item_class_name_lc} list and will be
+ able to run/view and import it.
+ </p>
+
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>Email</th>
+ <th></th>
+ </tr>
+ %for i, association in enumerate( item.users_shared_with ):
+ <% user = association.user %>
+ <tr>
+ <td>
+ ${user.email}
+ <a id="user-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
+ </td>
+ <td>
+ <div popupmenu="user-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ), unshare_user=trans.security.encode_id( user.id ) )}">Unshare</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+
+ <p>
+ <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
+ <span>Share with another user</span>
+ </a>
+
+ %else:
+
+ <p>You have not shared this ${item_class_name_lc} with any users.</p>
+
+ <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
+ <span>Share with a user</span>
+ </a>
+ <br>
+
+ %endif
+ </div>
</div>
- <div style="clear: both"></div>
- <div class="form-row">
- <input class="action-button" type="submit" name="Set Username" value="Set Username"/>
- </div>
- </form>
-%else:
- ## User has a public username, so private sharing and publishing options.
- <div class="indent" style="margin-top: 2em">
- <h3>Making ${item_class_name} Accessible via Link and Publishing It</h3>
-
- <div class="indent">
- %if item.importable:
- <%
- item_status = "accessible via link"
- if item.published:
- item_status = item_status + " and published"
- %>
- This ${item_class_name_lc} <strong>${item_status}</strong>.
- <div class="indent">
- <p>Anyone can view and import this ${item_class_name_lc} by visiting the following URL:
- <% url = h.url_for( action='display_by_username_and_slug', username=trans.get_user().username, slug=item.slug, qualified=True ) %>
- <blockquote>
- <a href="${url}" target="_top">${url}</a>
- </blockquote>
-
- %if item.published:
- This ${item_class_name_lc} is publicly listed and searchable in Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section.
- %endif
- </div>
-
- <p>You can:
- <div class="indent">
- <form action="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ) )}"
- method="POST">
- %if not item.published:
- ## Item is importable but not published. User can disable importable or publish.
- <input class="action-button" type="submit" name="disable_link_access" value="Disable Access to ${item_class_name} Link">
- <div class="toolParamHelp">Disables ${item_class_name_lc}'s link so that it is not accessible.</div>
- <br>
- <input class="action-button" type="submit" name="publish" value="Publish ${item_class_name}" method="POST">
- <div class="toolParamHelp">Publishes the ${item_class_name_lc} to Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section, where it is publicly listed and searchable.</div>
+ %endif
- <br>
- %else: ## item.published == True
- ## Item is importable and published. User can unpublish or disable import and unpublish.
- <input class="action-button" type="submit" name="unpublish" value="Unpublish ${item_class_name}">
- <div class="toolParamHelp">Removes ${item_class_name_lc} from Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section so that it is not publicly listed or searchable.</div>
- <br>
- <input class="action-button" type="submit" name="disable_link_access_and_unpubish" value="Disable Access to ${item_class_name} via Link and Unpublish">
- <div class="toolParamHelp">Disables ${item_class_name_lc}'s link so that it is not accessible and removes ${item_class_name_lc} from Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section so that it is not publicly listed or searchable.</div>
- %endif
-
- </form>
- </div>
-
- %else:
-
- This ${item_class_name_lc} is currently restricted so that only you and the users listed below can access it. You can:
- <p>
- <form action="${h.url_for( action='sharing', id=trans.security.encode_id(item.id) )}" method="POST">
- <input class="action-button" type="submit" name="make_accessible_via_link" value="Make ${item_class_name} Accessible via Link">
- <div class="toolParamHelp">Generates a web link that you can share with other people so that they can view and import the ${item_class_name_lc}.</div>
-
- <br>
- <input class="action-button" type="submit" name="make_accessible_and_publish" value="Make ${item_class_name} Accessible and Publish" method="POST">
- <div class="toolParamHelp">Makes the ${item_class_name_lc} accessible via link (see above) and publishes the ${item_class_name_lc} to Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section, where it is publicly listed and searchable.</div>
- </form>
-
- %endif
- </div>
-
- <h3>Sharing ${item_class_name} with Specific Users</h3>
-
- <div class="indent">
- %if item.users_shared_with:
-
- <p>
- The following users will see this ${item_class_name_lc} in their ${item_class_name_lc} list and will be
- able to run/view and import it.
- </p>
-
- <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr class="header">
- <th>Email</th>
- <th></th>
- </tr>
- %for i, association in enumerate( item.users_shared_with ):
- <% user = association.user %>
- <tr>
- <td>
- ${user.email}
- <a id="user-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
- </td>
- <td>
- <div popupmenu="user-${i}-popup">
- <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ), unshare_user=trans.security.encode_id( user.id ) )}">Unshare</a>
- </div>
- </td>
- </tr>
- %endfor
- </table>
-
- <p>
- <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
- <span>Share with another user</span>
- </a>
-
- %else:
-
- <p>You have not shared this ${item_class_name_lc} with any users.</p>
-
- <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
- <span>Share with a user</span>
- </a>
- <br>
-
- %endif
- </div>
- </div>
-%endif
-
-<p><br><br>
-<a href=${h.url_for( action="list" )}>Back to ${item_class_plural_name} List</a>
\ No newline at end of file
+ <p><br><br>
+ <a href=${h.url_for( action="list" )}>Back to ${item_class_plural_name} List</a>
+</%def>
\ No newline at end of file
diff -r a72dc4023e59 -r fe6e3c197d69 templates/workflow/display.mako
--- a/templates/workflow/display.mako Sat Jan 23 15:52:42 2010 -0500
+++ b/templates/workflow/display.mako Sun Jan 24 17:38:05 2010 -0500
@@ -73,7 +73,7 @@
%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:
- you own this workflow
+ your workflow
%endif
</%def>
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/a72dc4023e59
changeset: 3262:a72dc4023e59
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Sat Jan 23 15:52:42 2010 -0500
description:
Fix typo.
diffstat:
templates/library/common/library_permissions.mako | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (10 lines):
diff -r 5f8672ff2ae9 -r a72dc4023e59 templates/library/common/library_permissions.mako
--- a/templates/library/common/library_permissions.mako Sat Jan 23 15:28:25 2010 -0500
+++ b/templates/library/common/library_permissions.mako Sat Jan 23 15:52:42 2010 -0500
@@ -14,5 +14,5 @@
%endif
%if cntrller == 'library_admin' or trans.app.security_agent.can_manage_library_item( current_user_roles, library ):
- ${render_permission_form( library, library.name, h.url_for( controller='library_common', action='library_permissions', cntrller=cntrller, id=trans.security.encode_id( library.id ), cntrller=cntrller ), roles )}
+ ${render_permission_form( library, library.name, h.url_for( controller='library_common', action='library_permissions', cntrller=cntrller, id=trans.security.encode_id( library.id ) ), roles )}
%endif
1
0
25 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/5f8672ff2ae9
changeset: 3261:5f8672ff2ae9
user: jeremy goecks <jeremy.goecks(a)emory.edu>
date: Sat Jan 23 15:28:25 2010 -0500
description:
Integrate 'sharing via email' functionality into sharing framework so that all item sharing/viewing/publishing/security/tagging functionality uses the same code base and the same UI.
diffstat:
lib/galaxy/web/controllers/history.py | 41 +++++---
lib/galaxy/web/controllers/workflow.py | 15 ++-
static/scripts/galaxy.base.js | 4 +
static/scripts/packed/galaxy.base.js | 2 +-
templates/display_base.mako | 38 ++++++-
templates/grid_base.mako | 32 +------
templates/history/display.mako | 6 +-
templates/sharing_base.mako | 151 ++++++++++++++++----------------
templates/workflow/list.mako | 5 +-
9 files changed, 152 insertions(+), 142 deletions(-)
diffs (479 lines):
diff -r 8775859ad3f3 -r 5f8672ff2ae9 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Fri Jan 22 15:21:51 2010 -0500
+++ b/lib/galaxy/web/controllers/history.py Sat Jan 23 15:28:25 2010 -0500
@@ -105,18 +105,18 @@
return history.user.email
# Grid definition
title = "Histories shared with you by others"
- template='/history/grid.mako'
model_class = model.History
default_sort_key = "-update_time"
default_filter = {}
columns = [
- grids.GridColumn( "Name", key="name" ),
+ grids.GridColumn( "Name", key="name", attach_popup=True ), # link=( lambda item: dict( operation="View", id=item.id ) ), attach_popup=True ),
DatasetsByStateColumn( "Datasets (by state)", ncells=4 ),
grids.GridColumn( "Created", key="create_time", format=time_ago ),
grids.GridColumn( "Last Updated", key="update_time", format=time_ago ),
SharedByColumn( "Shared by", key="user_id" )
]
operations = [
+ grids.GridOperation( "View", allow_multiple=False, target="_top" ),
grids.GridOperation( "Clone" ),
grids.GridOperation( "Unshare" )
]
@@ -312,7 +312,11 @@
if 'operation' in kwargs:
ids = util.listify( kwargs.get( 'id', [] ) )
operation = kwargs['operation'].lower()
- if operation == "clone":
+ if operation == "view":
+ # Display history.
+ history = self.get_history( trans, ids[0], False)
+ return self.display_by_username_and_slug( trans, history.user.username, history.slug )
+ elif operation == "clone":
if not ids:
message = "Select a history to clone"
return self.shared_list_grid( trans, status='error', message=message, **kwargs )
@@ -487,26 +491,33 @@
datasets = query.all(),
user_owns_history = user_owns_history,
show_deleted = False )
-
+
@web.expose
def display_by_username_and_slug( self, trans, username, slug ):
- """ Display history based on a username and slug. """
- session = trans.sa_session
- user = session.query( model.User ).filter_by( username=username ).first()
- if user is None:
- raise web.httpexceptions.HTTPNotFound()
- history = trans.sa_session.query( model.History ).filter_by( user=user, slug=slug, deleted=False, importable=True ).first()
- if history is None:
+ """ Display history based on a username and slug. """
+
+ # Get history.
+ session = trans.sa_session
+ user = session.query( model.User ).filter_by( username=username ).first()
+ history_query_base = trans.sa_session.query( model.History ).filter_by( user=user, slug=slug, deleted=False )
+ if user is not None:
+ # User can view history if it's importable or if it's shared with him/her.
+ history = history_query_base.filter( or_( model.History.importable==True, model.History.users_shared_with.any( model.HistoryUserShareAssociation.user==trans.get_user() ) ) ).first()
+ else:
+ # User not logged in, so only way to view history is if it's importable.
+ history = history_query_base.filter_by( importable=True ).first()
+ if history is None:
raise web.httpexceptions.HTTPNotFound()
- query = trans.sa_session.query( model.HistoryDatasetAssociation ) \
+ # Get datasets.
+ query = trans.sa_session.query( model.HistoryDatasetAssociation ) \
.filter( model.HistoryDatasetAssociation.history == history ) \
.options( eagerload( "children" ) ) \
.join( "dataset" ).filter( model.Dataset.purged == False ) \
.options( eagerload_all( "dataset.actions" ) )
- # Do not show deleted datasets.
- query = query.filter( model.HistoryDatasetAssociation.deleted == False )
- return trans.stream_template_mako( "history/display.mako",
+ # Do not show deleted datasets.
+ query = query.filter( model.HistoryDatasetAssociation.deleted == False )
+ return trans.stream_template_mako( "history/display.mako",
item = history, item_data = query.all() )
@web.expose
diff -r 8775859ad3f3 -r 5f8672ff2ae9 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Fri Jan 22 15:21:51 2010 -0500
+++ b/lib/galaxy/web/controllers/workflow.py Sat Jan 23 15:28:25 2010 -0500
@@ -158,13 +158,18 @@
""" View workflow based on a username and slug. """
session = trans.sa_session
- # Get and verify user and stored workflow.
+ # Get history.
+ session = trans.sa_session
user = session.query( model.User ).filter_by( username=username ).first()
- if user is None:
- raise web.httpexceptions.HTTPNotFound()
- stored_workflow = trans.sa_session.query( model.StoredWorkflow ).filter_by( user=user, slug=slug, deleted=False, importable=True ).first()
+ workflow_query_base = trans.sa_session.query( model.StoredWorkflow ).filter_by( user=user, slug=slug, deleted=False )
+ if user is not None:
+ # User can view workflow if it's importable or if it's shared with him/her.
+ stored_workflow = workflow_query_base.filter( or_( model.StoredWorkflow.importable==True, model.StoredWorkflow.users_shared_with.any( model.StoredWorkflowUserShareAssociation.user==trans.get_user() ) ) ).first()
+ else:
+ # User not logged in, so only way to view workflow is if it's importable.
+ stored_workflow = workflow_query_base.filter_by( importable=True ).first()
if stored_workflow is None:
- raise web.httpexceptions.HTTPNotFound()
+ raise web.httpexceptions.HTTPNotFound()
# Get data for workflow's steps.
for step in stored_workflow.latest_workflow.steps:
diff -r 8775859ad3f3 -r 5f8672ff2ae9 static/scripts/galaxy.base.js
--- a/static/scripts/galaxy.base.js Fri Jan 22 15:21:51 2010 -0500
+++ b/static/scripts/galaxy.base.js Sat Jan 23 15:28:25 2010 -0500
@@ -37,6 +37,10 @@
if ( target == "_parent" ) {
f = window.parent;
}
+ else if
+ ( target == "_top" ) {
+ f = window.top;
+ }
f.location = href;
}
};
diff -r 8775859ad3f3 -r 5f8672ff2ae9 static/scripts/packed/galaxy.base.js
--- a/static/scripts/packed/galaxy.base.js Fri Jan 22 15:21:51 2010 -0500
+++ b/static/scripts/packed/galaxy.base.js Sat Jan 23 15:28:25 2010 -0500
@@ -1,1 +1,1 @@
-$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};jQuery(document).ready(function(){jQuery("a[confirm]").click(function(){return confirm(jQuery(this).attr("confirm"))});make_popup_menus()});function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function ensure_popup_helper(){if($("#popup-helper").length==0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"
100%"}).appendTo("body").hide()}}function make_popupmenu(d,c){ensure_popup_helper();var a=$(d);var b=$("<ul id='"+d.attr("id")+"-menu'></ul>");$.each(c,function(g,f){if(f){$("<li/>").html(g).click(f).appendTo(b)}else{$("<li class='head'/>").html(g).appendTo(b)}});var e=$("<div class='popmenu-wrapper'>");e.append(b).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(d,e)}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){var h=$(b).offset();$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}var array_length=function(a){if(a.length){return a.length}var b=0;for(element in a){b++}return b};var replace_
dbkey_select=function(){var c=$("select[name=dbkey]");var d=c.attr("value");if(c.length!=0){var e=$("<input id='dbkey-input' type='text'></input>");e.attr("size",40);e.attr("name",c.attr("name"));e.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var b=new Array();var a=new Object();c.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}b.push(h);a[h]=g;if(g==d){e.attr("value",h)}});if(e.attr("value")==""){e.attr("value","Click to Search or Select Build")}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};e.autocomplete(b,f);c.replaceWith(e);$("form").submit(function(){var i=$("#dbkey-input");if(i.length!=0){var h=i.attr("value");var g=a[h];if(g!=null&&g!=undefined){i.attr("value",g)}else{if(d!=""){i.attr("value",d)}else{i.attr("value","?")}}}})}};
\ No newline at end of file
+$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};jQuery(document).ready(function(){jQuery("a[confirm]").click(function(){return confirm(jQuery(this).attr("confirm"))});make_popup_menus()});function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function ensure_popup_helper(){if($("#popup-helper").length==0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",t
op:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_popupmenu(d,c){ensure_popup_helper();var a=$(d);var b=$("<ul id='"+d.attr("id")+"-menu'></ul>");$.each(c,function(g,f){if(f){$("<li/>").html(g).click(f).appendTo(b)}else{$("<li class='head'/>").html(g).appendTo(b)}});var e=$("<div class='popmenu-wrapper'>");e.append(b).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(d,e)}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){var h=$(b).offset();$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}var array_length=function(a){if(a.length){return a.length}var b=0;for(element
in a){b++}return b};var replace_dbkey_select=function(){var c=$("select[name=dbkey]");var d=c.attr("value");if(c.length!=0){var e=$("<input id='dbkey-input' type='text'></input>");e.attr("size",40);e.attr("name",c.attr("name"));e.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var b=new Array();var a=new Object();c.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}b.push(h);a[h]=g;if(g==d){e.attr("value",h)}});if(e.attr("value")==""){e.attr("value","Click to Search or Select Build")}var f={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};e.autocomplete(b,f);c.replaceWith(e);$("form").submit(function(){var i=$("#dbkey-input");if(i.length!=0){var h=i.attr("value");var g=a[h];if(g!=null&&g!=undefined){i.attr("value",g)}else{if(d!=""){i.attr("value",d)}else{i.
attr("value","?")}}}})}};
\ No newline at end of file
diff -r 8775859ad3f3 -r 5f8672ff2ae9 templates/display_base.mako
--- a/templates/display_base.mako Fri Jan 22 15:21:51 2010 -0500
+++ b/templates/display_base.mako Sat Jan 23 15:28:25 2010 -0500
@@ -1,4 +1,12 @@
-<%inherit file="/base_panels.mako"/>
+<%!
+ def inherit( context ):
+ if context.get('no_panels'):
+ return '/base.mako'
+ else:
+ return '/base_panels.mako'
+ from galaxy import model
+%>
+<%inherit file="${inherit( context )}"/>
<%namespace file="./tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
<%!
@@ -10,7 +18,7 @@
<%def name="get_class_display_name( a_class )">
<%
## Start with exceptions, end with default.
- if a_class is StoredWorkflow:
+ if a_class is model.StoredWorkflow:
return "Workflow"
else:
return a_class.__name__
@@ -18,7 +26,7 @@
</%def>
<%def name="title()">
- Galaxy :: ${iff( item.published, "Published ", "Accessible " ) + self.get_class_display_name( item.__class__ )} : ${item.name}
+ Galaxy | ${iff( item.published, "Published ", iff( item.importable , "Accessible ", "Shared " ) ) + self.get_class_display_name( item.__class__ )} | ${item.name}
</%def>
<%def name="init()">
@@ -84,6 +92,12 @@
<% return item.name %>
</%def>
+##
+## When page has no panels, center panel is body.
+##
+<%def name="body()">
+ ${self.center_panel()}
+</%def>
##
## Page content. Pages that inherit this page should override render_item_links() and render_item()
@@ -101,12 +115,18 @@
%>
<div class="unified-panel-header" unselectable="on">
- %if item.published:
- <div class="unified-panel-header-inner">
- <a href="${href_to_all_items}">Published ${item_plural}</a> |
- <a href="${href_to_user_items}">${item.user.username}</a> | ${self.get_item_name( item )}
- </div>
- %endif
+ <div class="unified-panel-header-inner">
+ %if item.published:
+ <a href="${href_to_all_items}">Published ${item_plural}</a> |
+ <a href="${href_to_user_items}">${item.user.username}</a>
+ %elif item.importable:
+ Accessible ${self.get_class_display_name( item.__class__ )}
+ %else:
+ ## Item shared with user.
+ Shared ${self.get_class_display_name( item.__class__ )}
+ %endif
+ | ${self.get_item_name( item )}
+ </div>
</div>
<div class="unified-panel-body">
diff -r 8775859ad3f3 -r 5f8672ff2ae9 templates/grid_base.mako
--- a/templates/grid_base.mako Fri Jan 22 15:21:51 2010 -0500
+++ b/templates/grid_base.mako Sat Jan 23 15:28:25 2010 -0500
@@ -197,37 +197,7 @@
});
});
}
-
- // Overrides function in galaxy.base.js so that click does operation.
- function make_popup_menus()
- {
- jQuery( "div[popupmenu]" ).each( function() {
- var options = {};
- $(this).find( "a" ).each( function() {
- var confirmtext = $(this).attr( "confirm" ),
- href = $(this).attr( "href" ),
- target = $(this).attr( "target" );
- options[ $(this).text() ] = function() {
- if ( !confirmtext || confirm( confirmtext ) ) {
- if ( href.indexOf( "operation" ) > -1 ) {
- do_operation_from_href(href);
- } else {
- var f = window;
- if ( target == "_parent" ) {
- f = window.parent;
- }
- f.location = href;
- }
- }
- };
- });
- var b = $( "#" + $(this).attr( 'popupmenu' ) );
- make_popupmenu( b, options );
- $(this).remove();
- b.addClass( "popup" ).show();
- });
- }
-
+
// Initialize grid elements.
function init_grid_elements()
{
diff -r 8775859ad3f3 -r 5f8672ff2ae9 templates/history/display.mako
--- a/templates/history/display.mako Fri Jan 22 15:21:51 2010 -0500
+++ b/templates/history/display.mako Sat Jan 23 15:28:25 2010 -0500
@@ -229,11 +229,11 @@
<%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> |
+ <a href="${h.url_for( controller='/history', action='imp', id=trans.security.encode_id(history.id) )}">import and start using history</a>
%else:
- your history |
+ your history
%endif
- <a href="${self.get_history_link( history )}">${_('refresh')}</a>
+ ##<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
diff -r 8775859ad3f3 -r 5f8672ff2ae9 templates/sharing_base.mako
--- a/templates/sharing_base.mako Fri Jan 22 15:21:51 2010 -0500
+++ b/templates/sharing_base.mako Sat Jan 23 15:28:25 2010 -0500
@@ -67,27 +67,29 @@
<h2>Sharing and Publishing ${item_class_name} '${item.name}'</h2>
-<div class="indent" style="margin-top: 2em">
-<h3>Making ${item_class_name} Accessible via Link and Publishing It</h3>
+## Require that user have a public username before sharing or publishing an item.
+%if trans.get_user().username is None or trans.get_user().username is "":
+ To make a ${item_class_name_lc} accessible via link or publish it, you must create a public username:
+ <p>
+ <form action="${h.url_for( action='set_public_username', id=trans.security.encode_id( item.id ) )}"
+ method="POST">
+ <div class="form-row">
+ <label>Public Username:</label>
+ <div class="form-row-input">
+ <input type="text" name="username" size="40"/>
+ </div>
+ </div>
+ <div style="clear: both"></div>
+ <div class="form-row">
+ <input class="action-button" type="submit" name="Set Username" value="Set Username"/>
+ </div>
+ </form>
+%else:
+ ## User has a public username, so private sharing and publishing options.
+ <div class="indent" style="margin-top: 2em">
+ <h3>Making ${item_class_name} Accessible via Link and Publishing It</h3>
- <div class="indent">
- %if trans.get_user().username is None or trans.get_user().username is "":
- To make a ${item_class_name_lc} accessible via link or publish it, you must create a public username:
- <p>
- <form action="${h.url_for( action='set_public_username', id=trans.security.encode_id( item.id ) )}"
- method="POST">
- <div class="form-row">
- <label>Public Username:</label>
- <div class="form-row-input">
- <input type="text" name="username" size="40"/>
- </div>
- </div>
- <div style="clear: both"></div>
- <div class="form-row">
- <input class="action-button" type="submit" name="Set Username" value="Set Username"/>
- </div>
- </form>
- %else:
+ <div class="indent">
%if item.importable:
<%
item_status = "accessible via link"
@@ -101,12 +103,12 @@
<blockquote>
<a href="${url}" target="_top">${url}</a>
</blockquote>
-
+
%if item.published:
This ${item_class_name_lc} is publicly listed and searchable in Galaxy's <a href='${h.url_for( action='list_published' )}' target="_top">Published ${item_class_plural_name}</a> section.
%endif
</div>
-
+
<p>You can:
<div class="indent">
<form action="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ) )}"
@@ -128,78 +130,75 @@
<input class="action-button" type="submit" name="disable_link_access_and_unpubish" value="Disable Access to ${item_class_name} via Link and Unpublish">
<div class="toolParamHelp">Disables ${item_class_name_lc}'s link so that it is not accessible and removes ${item_class_name_lc} from Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section so that it is not publicly listed or searchable.</div>
%endif
-
+
</form>
</div>
-
+
%else:
-
+
This ${item_class_name_lc} is currently restricted so that only you and the users listed below can access it. You can:
<p>
<form action="${h.url_for( action='sharing', id=trans.security.encode_id(item.id) )}" method="POST">
<input class="action-button" type="submit" name="make_accessible_via_link" value="Make ${item_class_name} Accessible via Link">
<div class="toolParamHelp">Generates a web link that you can share with other people so that they can view and import the ${item_class_name_lc}.</div>
-
+
<br>
<input class="action-button" type="submit" name="make_accessible_and_publish" value="Make ${item_class_name} Accessible and Publish" method="POST">
<div class="toolParamHelp">Makes the ${item_class_name_lc} accessible via link (see above) and publishes the ${item_class_name_lc} to Galaxy's <a href='${h.url_for( action='list_published' )}' target='_top'>Published ${item_class_plural_name}</a> section, where it is publicly listed and searchable.</div>
</form>
-
+
%endif
- %endif
- </div>
+ </div>
-<h3>Sharing ${item_class_name} with Specific Users</h3>
+ <h3>Sharing ${item_class_name} with Specific Users</h3>
- <div class="indent">
- %if item.users_shared_with:
+ <div class="indent">
+ %if item.users_shared_with:
- <p>
- The following users will see this ${item_class_name_lc} in their ${item_class_name_lc} list and will be
- able to run/view and import it.
- </p>
+ <p>
+ The following users will see this ${item_class_name_lc} in their ${item_class_name_lc} list and will be
+ able to run/view and import it.
+ </p>
+
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>Email</th>
+ <th></th>
+ </tr>
+ %for i, association in enumerate( item.users_shared_with ):
+ <% user = association.user %>
+ <tr>
+ <td>
+ ${user.email}
+ <a id="user-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
+ </td>
+ <td>
+ <div popupmenu="user-${i}-popup">
+ <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ), unshare_user=trans.security.encode_id( user.id ) )}">Unshare</a>
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </table>
+
+ <p>
+ <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
+ <span>Share with another user</span>
+ </a>
+
+ %else:
+
+ <p>You have not shared this ${item_class_name_lc} with any users.</p>
- <ul class="manage-table-actions">
- <li>
- <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
- <span>Share with another user</span>
- </a>
- </li>
- </ul>
-
- <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr class="header">
- <th>Email</th>
- <th></th>
- </tr>
- %for i, association in enumerate( item.users_shared_with ):
- <% user = association.user %>
- <tr>
- <td>
- ${user.email}
- <a id="user-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
- </td>
- <td>
- <div popupmenu="user-${i}-popup">
- <a class="action-button" href="${h.url_for( action='sharing', id=trans.security.encode_id( item.id ), unshare_user=trans.security.encode_id( user.id ) )}">Unshare</a>
- </div>
- </td>
- </tr>
- %endfor
- </table>
-
- %else:
-
- <p>You have not shared this ${item_class_name_lc} with any users.</p>
+ <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
+ <span>Share with a user</span>
+ </a>
+ <br>
- <a class="action-button" href="${h.url_for( action='share', id=trans.security.encode_id(item.id) )}">
- <span>Share with a user</span>
- </a>
- <br>
-
- %endif
- </div>
-</div>
+ %endif
+ </div>
+ </div>
+%endif
<p><br><br>
<a href=${h.url_for( action="list" )}>Back to ${item_class_plural_name} List</a>
\ No newline at end of file
diff -r 8775859ad3f3 -r 5f8672ff2ae9 templates/workflow/list.mako
--- a/templates/workflow/list.mako Fri Jan 22 15:21:51 2010 -0500
+++ b/templates/workflow/list.mako Sat Jan 23 15:28:25 2010 -0500
@@ -82,8 +82,9 @@
<td>${len(workflow.latest_workflow.steps)}</td>
<td>
<div popupmenu="shared-${i}-popup">
- <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>
+ <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>
1
0
Hi,
i have tried to speed up the fasta-length calculation, because it was
very slow for large sequences. Find attached a new much faster tool (<1s
vs. 7min for a 8MB Fasta-File) that passes all old tests.
Thanks,
Bjoern
2
1
Is file type association case sensitive?
If file extensions "abc", "ABC", "Abc" represent the same data type, is it
also like that in Galaxy?
If not, how can one modify Galaxy to do that?
Thanks in advance,
TH
2
1
Hi,
(i'm using current galaxy_dist r3173:f7dee0438854)
when you have a tool in galaxy that creates multiple output datasets, the order in which you define them in the xml file is not preserved in the history.
I believe this is because galaxy collects the output objects in a dict. I made some changes (see the diff below) to use an odict() instead.
However this works only partially, the tool gets executed and the order of the output datasets is preserved, but instead of the message you normally see after executing a tool an error is raised (see below).
I don't know what went wrong and where, I particularly don't understand how the message.mako template works.
Alex
* Error
URL: http://127.0.0.1:8080/tool_runner/index
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/WebError-0.8a-py2.5.egg/weberror/evalexception/middleware.py', line 364 in respond
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Paste-1.6-py2.5.egg/paste/debug/prints.py', line 98 in __call__
environ, self.app)
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Paste-1.6-py2.5.egg/paste/wsgilib.py', line 539 in intercept_output
app_iter = application(environ, replacement_start_response)
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Beaker-1.4-py2.5.egg/beaker/middleware.py', line 152 in __call__
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Paste-1.6-py2.5.egg/paste/recursive.py', line 80 in __call__
return self.application(environ, start_response)
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Paste-1.6-py2.5.egg/paste/httpexceptions.py', line 632 in __call__
return self.application(environ, start_response)
File '/Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/web/framework/base.py', line 125 in __call__
body = self.call_body_method( method, trans, kwargs )
File '/Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/web/framework/base.py', line 144 in call_body_method
return method( trans, **kwargs )
File '/Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/web/controllers/tool_runner.py', line 59 in index
return trans.fill_template( template, history=history, toolbox=toolbox, tool=tool, util=util, add_frame=add_frame, **vars )
File '/Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/web/framework/__init__.py', line 593 in fill_template
return self.fill_template_mako( filename, **kwargs )
File '/Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/web/framework/__init__.py', line 604 in fill_template_mako
return template.render( **data )
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Mako-0.2.5-py2.5.egg/mako/template.py', line 133 in render
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Mako-0.2.5-py2.5.egg/mako/runtime.py', line 364 in _render
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Mako-0.2.5-py2.5.egg/mako/runtime.py', line 381 in _render_context
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Mako-0.2.5-py2.5.egg/mako/runtime.py', line 414 in _exec_template
File '/Users/alexrose/mc-galaxy/galaxy_dist/database/compiled_templates/base.mako.py', line 37 in render_body
__M_writer(unicode(next.body()))
File '/Users/alexrose/mc-galaxy/galaxy_dist/eggs/py2.5-noplatform/Mako-0.2.5-py2.5.egg/mako/runtime.py', line 255 in <lambda>
File '/Users/alexrose/mc-galaxy/galaxy_dist/database/compiled_templates/message.mako.py', line 45 in render_body
__M_writer(unicode(_(message)))
File '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/gettext.py', line 400 in ugettext
tmsg = self._catalog.get(message, missing)
TypeError: unhashable instance
* Diff
Index: /Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py Wed Dec 16 17:10:05 2009 +0100
+++ b/lib/galaxy/tools/__init__.py Fri Dec 18 16:20:53 2009 +0100
@@ -427,7 +427,7 @@
# Parse tool help
self.parse_help( root )
# Description of outputs produced by an invocation of the tool
- self.outputs = {}
+ self.outputs = odict()
out_elem = root.find("outputs")
if out_elem:
for data_elem in out_elem.findall("data"):
Index: /Users/alexrose/mc-galaxy/galaxy_dist/lib/galaxy/tools/actions/__init__.py
--- a/lib/galaxy/tools/actions/__init__.py Wed Dec 16 17:10:05 2009 +0100
+++ b/lib/galaxy/tools/actions/__init__.py Fri Dec 18 16:20:53 2009 +0100
@@ -7,6 +7,7 @@
from galaxy.jobs import JOB_OK
import galaxy.tools
from types import *
+from galaxy.util.odict import odict
import logging
log = logging.getLogger( __name__ )
@@ -117,7 +118,7 @@
input_values[ input.name ] = galaxy.tools.SelectToolParameterWrapper( input, input_values[ input.name ], tool.app, other_values = incoming )
else:
input_values[ input.name ] = galaxy.tools.InputValueWrapper( input, input_values[ input.name ], incoming )
- out_data = {}
+ out_data = odict()
# Collect any input datasets from the incoming parameters
inp_data = self.collect_input_datasets( tool, incoming, trans )
2
1
22 Jan '10
details: http://www.bx.psu.edu/hg/galaxy/rev/8775859ad3f3
changeset: 3260:8775859ad3f3
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Fri Jan 22 15:21:51 2010 -0500
description:
Fix the link to display the information about an expired version of a library dataset.
diffstat:
templates/library/common/ldda_info.mako | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diffs (12 lines):
diff -r ad5219e97c2f -r 8775859ad3f3 templates/library/common/ldda_info.mako
--- a/templates/library/common/ldda_info.mako Fri Jan 22 15:09:26 2010 -0500
+++ b/templates/library/common/ldda_info.mako Fri Jan 22 15:21:51 2010 -0500
@@ -105,7 +105,7 @@
<div class="toolFormTitle">Expired versions of ${ldda.name}</div>
%for expired_ldda in expired_lddas:
<div class="form-row">
- <a href="${h.url_for( controller='library_common', action='ldda_display_info', library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( expired_ldda.library_dataset.folder.id ), id=trans.security.encode_id( expired_ldda.id ) )}">${expired_ldda.name}</a>
+ <a href="${h.url_for( controller='library_common', action='ldda_display_info', cntrller=cntrller, library_id=trans.security.encode_id( library.id ), folder_id=trans.security.encode_id( expired_ldda.library_dataset.folder.id ), id=trans.security.encode_id( expired_ldda.id ) )}">${expired_ldda.name}</a>
</div>
%endfor
%endif
1
0