galaxy-dev
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- 10008 discussions

08 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/539d481c8f59
changeset: 2466:539d481c8f59
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue Jul 07 20:32:00 2009 -0400
description:
Fix for popup menus on history grid - no longer necessary to encode ids in the template.
1 file(s) affected in this change:
templates/history/grid.mako
diffs (12 lines):
diff -r 3bbb2d2caa5f -r 539d481c8f59 templates/history/grid.mako
--- a/templates/history/grid.mako Tue Jul 07 14:48:01 2009 -0400
+++ b/templates/history/grid.mako Tue Jul 07 20:32:00 2009 -0400
@@ -168,7 +168,7 @@
<div popupmenu="grid-${i}-popup">
%for operation in grid.operations:
%if operation.allowed( item ):
- <a class="action-button" href="${url( operation=operation.label, id=trans.security.encode_id( item.id ) )}">${operation.label}</a>
+ <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a>
%endif
%endfor
</div>
1
0

07 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/3bbb2d2caa5f
changeset: 2465:3bbb2d2caa5f
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue Jul 07 14:48:01 2009 -0400
description:
Fixes and additional functional tests associated with a user's private role:
- private roles are no longer displayed in the association forms, except for the currently selected user's private role
- a user's private role association can no longer be eliminated
- more than 1 association can no longer be made between a user and her private role
7 file(s) affected in this change:
lib/galaxy/model/mapping.py
lib/galaxy/security/__init__.py
lib/galaxy/web/controllers/admin.py
lib/galaxy/web/controllers/user.py
templates/admin/dataset_security/roles.mako
test/base/twilltestcase.py
test/functional/test_security_and_libraries.py
diffs (157 lines):
diff -r 4c3282337a4c -r 3bbb2d2caa5f lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Tue Jul 07 12:06:35 2009 -0400
+++ b/lib/galaxy/model/mapping.py Tue Jul 07 14:48:01 2009 -0400
@@ -624,7 +624,7 @@
user=relation( User, backref="roles" ),
non_private_roles=relation( User,
backref="non_private_roles",
- primaryjoin=( ( User.table.c.id == UserRoleAssociation.table.c.user_id ) & ( UserRoleAssociation.table.c.role_id == Role.table.c.id ) & not_( Role.table.c.type == 'private' ) ) ),
+ primaryjoin=( ( User.table.c.id == UserRoleAssociation.table.c.user_id ) & ( UserRoleAssociation.table.c.role_id == Role.table.c.id ) & not_( Role.table.c.name == User.table.c.email & Role.table.c.type == 'private' ) ) ),
role=relation( Role )
)
)
diff -r 4c3282337a4c -r 3bbb2d2caa5f lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py Tue Jul 07 12:06:35 2009 -0400
+++ b/lib/galaxy/security/__init__.py Tue Jul 07 14:48:01 2009 -0400
@@ -422,8 +422,11 @@
for a in user.non_private_roles + user.groups:
a.delete()
a.flush()
+ user.refresh()
for role in roles:
- self.associate_components( user=user, role=role )
+ # Make sure we are not creating an additional association with a PRIVATE role
+ if role not in user.roles:
+ self.associate_components( user=user, role=role )
for group in groups:
self.associate_components( user=user, group=group )
def set_entity_group_associations( self, groups=[], users=[], roles=[], delete_existing_assocs=True ):
diff -r 4c3282337a4c -r 3bbb2d2caa5f lib/galaxy/web/controllers/admin.py
--- a/lib/galaxy/web/controllers/admin.py Tue Jul 07 12:06:35 2009 -0400
+++ b/lib/galaxy/web/controllers/admin.py Tue Jul 07 14:48:01 2009 -0400
@@ -623,22 +623,35 @@
msg = util.restore_text( params.get( 'msg', '' ) )
messagetype = params.get( 'messagetype', 'done' )
user = trans.app.model.User.get( int( params.user_id ) )
+ private_role = trans.app.security_agent.get_private_user_role( user )
if params.get( 'user_roles_groups_edit_button', False ):
+ # Make sure the user is not dis-associating himself from his private role
+ out_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.out_roles ) ]
+ if private_role in out_roles:
+ msg += "You cannot eliminate a user's private role association. "
+ messagetype = 'error'
in_roles = [ trans.app.model.Role.get( x ) for x in util.listify( params.in_roles ) ]
+ out_groups = [ trans.app.model.Group.get( x ) for x in util.listify( params.out_groups ) ]
in_groups = [ trans.app.model.Group.get( x ) for x in util.listify( params.in_groups ) ]
- trans.app.security_agent.set_entity_user_associations( users=[ user ], roles=in_roles, groups=in_groups )
- user.refresh()
- msg += "User '%s' has been updated with %d associated roles and %d associated groups (private roles are not displayed)" % \
- ( user.email, len( in_roles ), len( in_groups ) )
- trans.response.send_redirect( web.url_for( action='users', msg=util.sanitize_text( msg ), messagetype=messagetype ) )
+ if in_roles:
+ trans.app.security_agent.set_entity_user_associations( users=[ user ], roles=in_roles, groups=in_groups )
+ user.refresh()
+ msg += "User '%s' has been updated with %d associated roles and %d associated groups (private roles are not displayed)" % \
+ ( user.email, len( in_roles ), len( in_groups ) )
+ trans.response.send_redirect( web.url_for( action='users', msg=util.sanitize_text( msg ), messagetype=messagetype ) )
in_roles = []
out_roles = []
in_groups = []
out_groups = []
- for role in trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ).order_by( trans.app.model.Role.table.c.name ).all():
+ for role in trans.app.model.Role.filter( trans.app.model.Role.table.c.deleted==False ) \
+ .order_by( trans.app.model.Role.table.c.name ).all():
if role in [ x.role for x in user.roles ]:
in_roles.append( ( role.id, role.name ) )
- else:
+ elif role.type != trans.app.model.Role.types.PRIVATE:
+ # There is a 1 to 1 mapping between a user and a PRIVATE role, so private roles should
+ # not be listed in the roles form fields, except for the currently selected user's private
+ # role, which should always be in in_roles. The check above is added as an additional
+ # precaution, since for a period of time we were including private roles in the form fields.
out_roles.append( ( role.id, role.name ) )
for group in trans.app.model.Group.filter( trans.app.model.Group.table.c.deleted==False ).order_by( trans.app.model.Group.table.c.name ).all():
if group in [ x.group for x in user.groups ]:
diff -r 4c3282337a4c -r 3bbb2d2caa5f lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py Tue Jul 07 12:06:35 2009 -0400
+++ b/lib/galaxy/web/controllers/user.py Tue Jul 07 14:48:01 2009 -0400
@@ -81,7 +81,6 @@
@web.expose
def login( self, trans, email='', password='' ):
- log.debug( "###IN login, email:%s, password: %s" % ( email, password ))
email_error = password_error = None
# Attempt login
if trans.app.config.require_login:
diff -r 4c3282337a4c -r 3bbb2d2caa5f templates/admin/dataset_security/roles.mako
--- a/templates/admin/dataset_security/roles.mako Tue Jul 07 12:06:35 2009 -0400
+++ b/templates/admin/dataset_security/roles.mako Tue Jul 07 14:48:01 2009 -0400
@@ -44,7 +44,7 @@
%endif
%if len( roles ) == 0:
- There are no Galaxy roles
+ There are no non-private Galaxy roles
%else:
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
<%
diff -r 4c3282337a4c -r 3bbb2d2caa5f test/base/twilltestcase.py
--- a/test/base/twilltestcase.py Tue Jul 07 12:06:35 2009 -0400
+++ b/test/base/twilltestcase.py Tue Jul 07 14:48:01 2009 -0400
@@ -816,16 +816,23 @@
check_str = "User '%s' has been marked as purged." % email
self.check_page_for_string( check_str )
self.home()
- def associate_roles_and_groups_with_user( self, user_id, email, role_ids=[], group_ids=[] ):
+ 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='' ):
self.home()
url = "%s/admin/user?user_id=%s&user_roles_groups_edit_button=Save" % ( self.url, user_id )
- if role_ids:
- url += "&in_roles=%s" % ','.join( role_ids )
- if group_ids:
- url += "&in_groups=%s" % ','.join( group_ids )
+ if in_role_ids:
+ url += "&in_roles=%s" % ','.join( in_role_ids )
+ if out_role_ids:
+ url += "&out_roles=%s" % ','.join( out_role_ids )
+ if in_group_ids:
+ url += "&in_groups=%s" % ','.join( in_group_ids )
+ if out_group_ids:
+ url += "&out_groups=%s" % ','.join( out_group_ids )
self.visit_url( url )
- check_str = "User '%s' has been updated with %d associated roles and %d associated groups" % ( email, len( role_ids ), len( group_ids ) )
- self.check_page_for_string( check_str )
+ if check_str:
+ self.check_page_for_string( check_str )
self.home()
# Tests associated with roles
diff -r 4c3282337a4c -r 3bbb2d2caa5f test/functional/test_security_and_libraries.py
--- a/test/functional/test_security_and_libraries.py Tue Jul 07 12:06:35 2009 -0400
+++ b/test/functional/test_security_and_libraries.py Tue Jul 07 14:48:01 2009 -0400
@@ -72,6 +72,11 @@
self.home()
self.visit_url( "%s/admin/user?user_id=%s" % ( self.url, 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( str( 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"""
@@ -430,7 +435,9 @@
group_ids = []
for uga in admin_user.groups:
group_ids.append( str( uga.group_id ) )
- self.associate_roles_and_groups_with_user( str( admin_user.id ), str( admin_user.email ), role_ids=role_ids, group_ids=group_ids )
+ 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( str( admin_user.id ), str( admin_user.email ),
+ in_role_ids=role_ids, in_group_ids=group_ids, check_str=check_str )
admin_user.refresh()
# admin_user should now be associated with 4 roles: private, role_one, role_two, role_three
if len( admin_user.roles ) != 4:
1
0

07 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/4c3282337a4c
changeset: 2464:4c3282337a4c
user: guru
date: Tue Jul 07 12:06:35 2009 -0400
description:
A bug fix for extract genomic dna to handle invalid chromosomes correctly.
1 file(s) affected in this change:
tools/extract/extract_genomic_dna.py
diffs (21 lines):
diff -r 3a4561684257 -r 4c3282337a4c tools/extract/extract_genomic_dna.py
--- a/tools/extract/extract_genomic_dna.py Mon Jul 06 20:41:24 2009 -0400
+++ b/tools/extract/extract_genomic_dna.py Tue Jul 07 12:06:35 2009 -0400
@@ -117,7 +117,7 @@
first_invalid_line = i + 1
invalid_line = line
continue
- elif seq_path and os.path.exists( seq_path ):
+ elif seq_path and os.path.isfile( seq_path ):
if chrom in twobits:
t = twobits[chrom]
else:
@@ -133,7 +133,7 @@
invalid_line = line
continue
else:
- warning = "Chrom '%s' was not found for build '%s'. " % ( chrom, dbkey )
+ warning = "Chromosome by name '%s' was not found for build '%s'. " % ( chrom, dbkey )
warnings.append( warning )
skipped_lines += 1
if not invalid_line:
1
0
Hello Galaxy team and Eckart,
It seems questions about zero/one based coordinates are frequent by new
galaxy users.
Some time ago I wrote a short summary (with screen shots) about the
different between one-based and zero-based coordinates in UCSC browser
(and by extension - in galaxy).
You're welcome to put it on your wiki, if you'd like.
-Gordon.
Eckart Bindewald wrote, On 07/07/2009 02:14 PM:
> Hello:
> thank you for providing the Galaxy server, it is a very impressive
> web application. I have a seemingly dumb but important question, and
> I could not find the information anywhere: what is the precise
> definition of an interval? Or: has the first residue of a chromosome
> the index zero or the index one? Is the end residue (the second
> number of an interval) the last residue of the interval, or one
> residue downstream with respect to the last residue included in the
> interval?
> Maybe questions like this can be included in the FAQ...
>
> Thanks in advance,
>
> Eckart Bindewald
>
> _______________________________________________
> galaxy-bugs mailing list
> galaxy-bugs(a)bx.psu.edu
> http://mail.bx.psu.edu/cgi-bin/mailman/listinfo/galaxy-bugs
1
0

07 Jul '09
details: http://www.bx.psu.edu/hg/galaxy/rev/3a4561684257
changeset: 2463:3a4561684257
user: Nate Coraor <nate(a)bx.psu.edu>
date: Mon Jul 06 20:41:24 2009 -0400
description:
Fix deleted user access bug discovered by Pieter Neerincx
2 file(s) affected in this change:
lib/galaxy/web/framework/__init__.py
static/user_disabled.html
diffs (74 lines):
diff -r 8ad73e08978e -r 3a4561684257 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Mon Jun 29 17:04:18 2009 -0400
+++ b/lib/galaxy/web/framework/__init__.py Mon Jul 06 20:41:24 2009 -0400
@@ -147,6 +147,9 @@
self.workflow_building_mode = False
# Always have a valid galaxy session
self.__ensure_valid_session( session_cookie )
+ # Prevent deleted users from accessing Galaxy
+ if self.app.config.use_remote_user and self.galaxy_session.user.deleted:
+ self.response.send_redirect( url_for( '/static/user_disabled.html' ) )
if self.app.config.require_login:
self.__ensure_logged_in_user( environ )
def setup_i18n( self ):
@@ -279,6 +282,9 @@
invalidate_existing_session = True
log.warning( "User '%s' is an external user with an existing session, invalidating session since external auth is disabled",
galaxy_session.user.email )
+ elif galaxy_session is not None and galaxy_session.user is not None and galaxy_session.user.deleted:
+ invalidate_existing_session = True
+ log.warning( "User '%s' is marked deleted, invalidating session" % galaxy_session.user.email )
# Do we need to invalidate the session for some reason?
if invalidate_existing_session:
prev_galaxy_session = galaxy_session
@@ -300,6 +306,9 @@
if prev_galaxy_session:
objects_to_flush.append( prev_galaxy_session )
sa_session.flush( objects_to_flush )
+ # If the old session was invalid, get a new history with our new session
+ if invalidate_existing_session:
+ self.new_history()
def __ensure_logged_in_user( self, environ ):
allowed_paths = (
url_for( controller='root', action='index' ),
@@ -368,8 +377,6 @@
# We set default user permissions, before we log in and set the default history permissions
self.app.security_agent.user_set_default_permissions( user )
#self.log_event( "Automatically created account '%s'", user.email )
- elif user.deleted:
- return self.show_error_message( "Your account is no longer valid, contact your Galaxy administrator to activate your account." )
return user
def __update_session_cookie( self, name='galaxysession' ):
"""
diff -r 8ad73e08978e -r 3a4561684257 static/user_disabled.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/user_disabled.html Mon Jul 06 20:41:24 2009 -0400
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en">
+ <head>
+ <title>Galaxy</title>
+ <style type="text/css">
+ body {
+ min-width: 500px;
+ text-align: center;
+ }
+ .errormessage {
+ font: 75%% verdana, "Bitstream Vera Sans", geneva, arial, helvetica, helve, sans-serif;
+ padding: 10px;
+ margin: 100px auto;
+ min-height: 32px;
+ max-width: 500px;
+ border: 1px solid #AA6666;
+ background-color: #FFCCCC;
+ text-align: left;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="errormessage">
+ <h4>Account Disabled</h4>
+ <p>Your account is no longer valid, contact your Galaxy administrator to activate your account.</p>
+ </div>
+ </body>
+</html>
1
0
Hello,
What needs to be configured in order to limit users to their own datasets ?
What I mean is that on my local server (using external authentication,
but no security groups/roles defined), I can use the following URL to
view my datasets;
http://rave.cshl.edu/galaxy/datasets/35819/display/index
But I can also change the dataset ID and view any other file, regardless
of whether it is mine or not.
I'd like to block access to other users' datasets (but I prefer not to
create specialized roles/groups).
Thanks,
Gordon.
2
1

30 Jun '09
details: http://www.bx.psu.edu/hg/galaxy/rev/533ae45c4440
changeset: 2460:533ae45c4440
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Mon Jun 29 16:30:16 2009 -0400
description:
Many history-related feature enhancements, some fixes and enhanced functional tests:
- history sharing is now modeled after workflow sharing - fixes ticket # 63.
- all history features pass encoded history ids between requests
- new, empty histories are no longer created when a user logs in, instead their last accessed history is displayed
- some other things I'm forgetting, I'm sure
This commit also includes a fix for remote user authentication where private roles and default permissions were not created for users ( Ross's and Assaf's issues ).
Many functional test enhancements.
30 file(s) affected in this change:
lib/galaxy/model/__init__.py
lib/galaxy/model/mapping.py
lib/galaxy/model/migrate/versions/0007_sharing_histories.py
lib/galaxy/security/__init__.py
lib/galaxy/tools/parameters/basic.py
lib/galaxy/web/controllers/history.py
lib/galaxy/web/controllers/root.py
lib/galaxy/web/controllers/user.py
lib/galaxy/web/controllers/workflow.py
lib/galaxy/web/framework/__init__.py
lib/galaxy/web/framework/helpers/grids.py
lib/galaxy/web/security/__init__.py
templates/grid.mako
templates/history/grid.mako
templates/history/list_as_xml.mako
templates/history/list_shared.mako
templates/history/options.mako
templates/history/permissions.mako
templates/history/rename.mako
templates/history/share.mako
templates/history/sharing.mako
test/base/twilltestcase.py
test/functional/__init__.py
test/functional/test_DNAse_flanked_genes.py
test/functional/test_get_data.py
test/functional/test_history_functions.py
test/functional/test_metadata_editing.py
test/functional/test_security_and_libraries.py
test/functional/test_sniffing_and_metadata_settings.py
test/functional/test_toolbox.py
diffs (truncated from 3697 to 3000 lines):
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/model/__init__.py Mon Jun 29 16:30:16 2009 -0400
@@ -214,22 +214,29 @@
if genome_build not in [None, '?']:
self.genome_build = genome_build
self.datasets.append( dataset )
- def copy( self, target_user = None ):
+ def copy( self, name=None, target_user=None ):
+ if not name:
+ name = self.name
if not target_user:
target_user = self.user
- des = History( user = target_user )
- des.flush()
- des.name = self.name
+ new_history = History( name=name, user=target_user )
+ new_history.flush()
for data in self.datasets:
- new_data = data.copy( copy_children = True, target_history = des )
- des.add_dataset( new_data, set_hid = False )
+ new_data = data.copy( copy_children=True, target_history=new_history )
+ new_history.add_dataset( new_data, set_hid = False )
new_data.flush()
- des.hid_counter = self.hid_counter
- des.flush()
- return des
+ new_history.hid_counter = self.hid_counter
+ new_history.flush()
+ return new_history
@property
def activatable_datasets( self ):
- return [ hda for hda in self.datasets if not hda.dataset.deleted ] #this needs to be a list
+ # This needs to be a list
+ return [ hda for hda in self.datasets if not hda.dataset.deleted ]
+
+class HistoryUserShareAssociation( object ):
+ def __init__( self ):
+ self.history = None
+ self.user = None
class UserRoleAssociation( object ):
def __init__( self, user, role ):
@@ -988,7 +995,7 @@
remote_host=None,
remote_addr=None,
referer=None,
- current_history_id=None,
+ current_history=None,
session_key=None,
is_valid=False,
prev_session_id=None ):
@@ -997,12 +1004,11 @@
self.remote_host = remote_host
self.remote_addr = remote_addr
self.referer = referer
- self.current_history_id = current_history_id
+ self.current_history = current_history
self.session_key = session_key
self.is_valid = is_valid
self.prev_session_id = prev_session_id
self.histories = []
-
def add_history( self, history, association=None ):
if association is None:
self.histories.append( GalaxySessionToHistoryAssociation( self, history ) )
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/model/mapping.py Mon Jun 29 16:30:16 2009 -0400
@@ -56,7 +56,14 @@
Column( "hid_counter", Integer, default=1 ),
Column( "deleted", Boolean, index=True, default=False ),
Column( "purged", Boolean, index=True, default=False ),
- Column( "genome_build", TrimmedString( 40 ) ) )
+ Column( "genome_build", TrimmedString( 40 ) ),
+ Column( "importable", Boolean, default=False ) )
+
+HistoryUserShareAssociation.table = Table( "history_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
HistoryDatasetAssociation.table = Table( "history_dataset_association", metadata,
Column( "id", Integer, primary_key=True ),
@@ -575,6 +582,11 @@
active_datasets=relation( HistoryDatasetAssociation, primaryjoin=( ( HistoryDatasetAssociation.table.c.history_id == History.table.c.id ) & ( not_( HistoryDatasetAssociation.table.c.deleted ) ) ), order_by=asc( HistoryDatasetAssociation.table.c.hid ), lazy=False, viewonly=True )
) )
+assign_mapper( context, HistoryUserShareAssociation, HistoryUserShareAssociation.table,
+ properties=dict( user=relation( User, backref='histories_shared_by_others' ),
+ history=relation( History, backref='users_shared_with' )
+ ) )
+
assign_mapper( context, User, User.table,
properties=dict( histories=relation( History, backref="user",
order_by=desc(History.table.c.update_time) ),
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/model/migrate/versions/0007_sharing_histories.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/galaxy/model/migrate/versions/0007_sharing_histories.py Mon Jun 29 16:30:16 2009 -0400
@@ -0,0 +1,59 @@
+from sqlalchemy import *
+from migrate import *
+
+import datetime
+now = datetime.datetime.utcnow
+
+# Need our custom types, but don't import anything else from model
+from galaxy.model.custom_types import *
+
+metadata = MetaData( migrate_engine )
+
+HistoryUserShareAssociation_table = Table( "history_user_share_association", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
+ Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True )
+ )
+
+def upgrade():
+ # Load existing tables
+ metadata.reflect()
+ # Create the history_user_share_association table
+ try:
+ HistoryUserShareAssociation_table.create()
+ except Exception, e:
+ log.debug( "Creating history_user_share_association table failed: %s" % str( e ) )
+ # Add 1 column to the history table
+ try:
+ History_table = Table( "history", metadata, autoload=True )
+ except NoSuchTableError:
+ History_table = None
+ log.debug( "Failed loading table history" )
+ if History_table:
+ try:
+ col = Column( 'importable', Boolean, index=True, default=False )
+ col.create( History_table )
+ assert col is History_table.c.importable
+ except Exception, e:
+ log.debug( "Adding column 'importable' to history table failed: %s" % ( str( e ) ) )
+
+def downgrade():
+ # Load existing tables
+ metadata.reflect()
+ # Drop 1 column from the history table
+ try:
+ History_table = Table( "history", metadata, autoload=True )
+ except NoSuchTableError:
+ History_table = None
+ log.debug( "Failed loading table history" )
+ if History_table:
+ try:
+ col = History_table.c.importable
+ col.drop()
+ except Exception, e:
+ log.debug( "Dropping column 'importable' from history table failed: %s" % ( str( e ) ) )
+ # Drop the history_user_share_association table
+ try:
+ HistoryUserShareAssociation_table.drop()
+ except Exception, e:
+ log.debug( "Dropping history_user_share_association table failed: %s" % str( e ) )
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/security/__init__.py Mon Jun 29 16:30:16 2009 -0400
@@ -275,6 +275,8 @@
def set_all_dataset_permissions( self, dataset, permissions={} ):
# Set new permissions on a dataset, eliminating all current permissions
# Delete all of the current permissions on the dataset
+ # TODO: If setting ACCESS permission, at least 1 user must have every role associated with this dataset,
+ # or the dataset is inaccessible. See admin/library_dataset_dataset_association()
for dp in dataset.actions:
dp.delete()
dp.flush()
@@ -285,8 +287,9 @@
for dp in [ self.model.DatasetPermissions( action, dataset, role ) for role in roles ]:
dp.flush()
def set_dataset_permission( self, dataset, permission={} ):
- # TODO: is this method needed - see above method
# Set a specific permission on a dataset, leaving all other current permissions on the dataset alone
+ # TODO: If setting ACCESS permission, at least 1 user must have every role associated with this dataset,
+ # or the dataset is inaccessible. See admin/library_dataset_dataset_association()
for action, roles in permission.items():
if isinstance( action, Action ):
action = action.action
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/tools/parameters/basic.py Mon Jun 29 16:30:16 2009 -0400
@@ -1106,7 +1106,7 @@
except IndexError:
pass #no valid options
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.history
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if value is not None:
if type( value ) != list:
@@ -1170,11 +1170,10 @@
if trans.workflow_building_mode:
return DummyDataset()
assert trans is not None, "DataToolParameter requires a trans"
- history = trans.history
+ history = trans.get_history()
assert history is not None, "DataToolParameter requires a history"
if self.optional:
return None
- history = trans.history
most_recent_dataset = [None]
filter_value = None
if self.options:
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/controllers/history.py
--- a/lib/galaxy/web/controllers/history.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/controllers/history.py Mon Jun 29 16:30:16 2009 -0400
@@ -1,6 +1,9 @@
from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, iff, grids
from galaxy import util
+from galaxy.model.mapping import desc
+from galaxy.model.orm import *
+from galaxy.util.json import *
import webhelpers, logging
from datetime import datetime
from cgi import escape
@@ -11,16 +14,19 @@
SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error"
class HistoryListGrid( grids.Grid ):
-
title = "Stored histories"
model_class = model.History
default_sort_key = "-create_time"
columns = [
grids.GridColumn( "Name", key="name",
- link=( lambda item: iff( item.deleted, None, dict( operation="switch", id=item.id ) ) ),
- attach_popup=True ),
+ link=( lambda item: iff( item.deleted, None, dict( operation="switch", id=item.id ) ) ),
+ attach_popup=True ),
grids.GridColumn( "Datasets (by state)", method='_build_datasets_by_state', ncells=4 ),
- grids.GridColumn( "Status", method='_build_status' ),
+ grids.GridColumn( "Status", method='_build_status',
+ link=( lambda item: iff( item.users_shared_with,
+ dict( operation="sharing", id=item.id ),
+ None ) ),
+ attach_popup=False ),
grids.GridColumn( "Age", key="create_time", format=time_ago ),
grids.GridColumn( "Last update", key="update_time", format=time_ago ),
# Valid for filtering but invisible
@@ -39,13 +45,10 @@
grids.GridColumnFilter( "All", args=dict( deleted='All' ) )
]
default_filter = dict( deleted=False )
-
def get_current_item( self, trans ):
- return trans.history
-
+ return trans.get_history()
def apply_default_filter( self, trans, query ):
return query.filter_by( user=trans.user, purged=False )
-
def _build_datasets_by_state( self, trans, history ):
rval = []
for state in ( 'ok', 'running', 'queued', 'error' ):
@@ -55,10 +58,11 @@
else:
rval.append( '' )
return rval
-
def _build_status( self, trans, history ):
if history.deleted:
return "deleted"
+ elif history.users_shared_with:
+ return "shared"
return ""
class HistoryController( BaseController ):
@@ -68,9 +72,7 @@
return ""
@web.expose
def list_as_xml( self, trans ):
- """
- XML history list for functional tests
- """
+ """XML history list for functional tests"""
return trans.fill_template( "/history/list_as_xml.mako" )
list_grid = HistoryListGrid()
@@ -79,29 +81,32 @@
@web.require_login( "work with multiple histories" )
def list( self, trans, **kwargs ):
"""List all available histories"""
- current_history = trans.history
+ current_history = trans.get_history()
status = message = None
if 'operation' in kwargs:
+ history_ids = util.listify( kwargs.get( 'id', [] ) )
+ histories = []
+ shared_by_others = []
operation = kwargs['operation'].lower()
if operation == "share":
return self.share( trans, **kwargs )
elif operation == "rename":
return self.rename( trans, **kwargs )
+ elif operation == 'sharing':
+ return self.sharing( trans, id=kwargs['id'] )
# Display no message by default
status, message = None, None
refresh_history = False
# Load the histories and ensure they all belong to the current user
- history_ids = util.listify( kwargs.get( 'id', [] ) )
- histories = []
- for hid in history_ids:
- history = model.History.get( hid )
+ for history_id in history_ids:
+ history = get_history( trans, history_id )
if history:
# Ensure history is owned by current user
if history.user_id != None and trans.user:
assert trans.user.id == history.user_id, "History does not belong to current user"
histories.append( history )
else:
- log.warn( "Invalid history id '%r' passed to list", hid )
+ log.warn( "Invalid history id '%r' passed to list", history_id )
if histories:
if operation == "switch":
status, message = self._list_switch( trans, histories )
@@ -110,33 +115,36 @@
elif operation == "delete":
status, message = self._list_delete( trans, histories )
if current_history in histories:
+ # Deleted the current history, so a new, empty history was
+ # created automatically, and we need to refresh the history frame
trans.template_context['refresh_frames'] = ['history']
elif operation == "undelete":
status, message = self._list_undelete( trans, histories )
trans.sa_session.flush()
# Render the list view
- return self.list_grid( trans, status=status, message=message, **kwargs )
+ return self.list_grid( trans, status=status, message=message, template='/history/grid.mako', **kwargs )
def _list_delete( self, trans, histories ):
"""Delete histories"""
n_deleted = 0
deleted_current = False
+ message_parts = []
for history in histories:
- if not history.deleted:
+ if history.users_shared_with:
+ message_parts.append( "History (%s) has been shared with others, unshare it before deleting it. " % history.name )
+ elif not history.deleted:
# We'll not eliminate any DefaultHistoryPermissions in case we undelete the history later
- # Mark history as deleted in db
history.deleted = True
# If deleting the current history, make a new current.
- if history == trans.history:
+ if history == trans.get_history():
deleted_current = True
trans.new_history()
- trans.log_event( "History id %d marked as deleted" % history.id )
+ trans.log_event( "History (%s) marked as deleted" % history.name )
n_deleted += 1
status = SUCCESS
- message_parts = []
if n_deleted:
- message_parts.append( "Deleted %d histories." % n_deleted )
+ message_parts.append( "Deleted %d histories. " % n_deleted )
if deleted_current:
- message_parts.append( "Your active history was deleted, a new empty history is now active.")
+ message_parts.append( "Your active history was deleted, a new empty history is now active. " )
status = INFO
return ( status, " ".join( message_parts ) )
def _list_undelete( self, trans, histories ):
@@ -151,20 +159,20 @@
if not history.default_permissions:
# For backward compatibility - for a while we were deleting all DefaultHistoryPermissions on
# the history when we deleted the history. We are no longer doing this.
- # Need to add default DefaultHistoryPermissions since they were deleted when the history was deleted
+ # Need to add default DefaultHistoryPermissions in case they were deleted when the history was deleted
default_action = trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS
private_user_role = trans.app.security_agent.get_private_user_role( history.user )
default_permissions = {}
default_permissions[ default_action ] = [ private_user_role ]
trans.app.security_agent.history_set_default_permissions( history, default_permissions )
n_undeleted += 1
- trans.log_event( "History id %d marked as undeleted" % history.id )
+ trans.log_event( "History (%s) %d marked as undeleted" % history.name )
status = SUCCESS
message_parts = []
if n_undeleted:
message_parts.append( "Undeleted %d histories." % n_undeleted )
if n_already_purged:
- message_parts.append( "%d have already been purged and cannot be undeleted." % n_already_purged )
+ message_parts.append( "%d histories have already been purged and cannot be undeleted." % n_already_purged )
status = WARNING
return status, "".join( message_parts )
def _list_switch( self, trans, histories ):
@@ -172,25 +180,39 @@
new_history = histories[0]
galaxy_session = trans.get_galaxy_session()
try:
- association = trans.app.model.GalaxySessionToHistoryAssociation.filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
+ association = trans.app.model.GalaxySessionToHistoryAssociation \
+ .filter_by( session_id=galaxy_session.id, history_id=trans.security.decode_id( new_history.id ) ).first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
new_history.flush()
trans.set_history( new_history )
- trans.log_event( "History switched to id: %s, name: '%s'" % (str(new_history.id), new_history.name ) )
# No message
return None, None
+ @web.expose
+ def list_shared( self, trans, **kwd ):
+ """List histories shared with current user by others"""
+ params = util.Params( kwd )
+ msg = util.restore_text( params.get( 'msg', '' ) )
+ shared_by_others = trans.sa_session \
+ .query( model.HistoryUserShareAssociation ) \
+ .filter_by( user=trans.user ) \
+ .join( 'history' ) \
+ .filter( model.History.deleted == False ) \
+ .order_by( desc( model.History.update_time ) ) \
+ .all()
+ return trans.fill_template( "/history/list_shared.mako", shared_by_others=shared_by_others, msg=msg, messagetype='done' )
@web.expose
def delete_current( self, trans ):
"""Delete just the active history -- this does not require a logged in user."""
history = trans.get_history()
+ if history.users_shared_with:
+ return trans.show_error_message( "History (%s) has been shared with others, unshare it before deleting it. " % history.name )
if not history.deleted:
history.deleted = True
history.flush()
trans.log_event( "History id %d marked as deleted" % history.id )
- # Regardless of whether it was previously deleted, we make a new
- # history active
+ # Regardless of whether it was previously deleted, we make a new history active
trans.new_history()
return trans.show_ok_message( "History deleted, a new history is active", refresh_frames=['history'] )
@web.expose
@@ -200,7 +222,7 @@
# user (if logged in) or the current history
assert history is not None
if history.user is None:
- assert history == trans.history
+ assert history == trans.get_history()
else:
assert history.user == trans.user
# Rename
@@ -208,48 +230,49 @@
trans.sa_session.flush()
@web.expose
def imp( self, trans, id=None, confirm=False, **kwd ):
- # TODO clean this up and make sure functionally correct
+ """Import another user's history via a shared URL"""
msg = ""
user = trans.get_user()
user_history = trans.get_history()
if not id:
- return trans.show_error_message( "You must specify a history you want to import.")
- id = trans.security.decode_id( id )
- import_history = trans.app.model.History.get( id )
+ return trans.show_error_message( "You must specify a history you want to import." )
+ import_history = get_history( trans, id )
if not import_history:
return trans.show_error_message( "The specified history does not exist.")
+ if not import_history.importable:
+ error( "The owner of this history has disabled imports via this link." )
if user:
if import_history.user_id == user.id:
- return trans.show_error_message( "You cannot import your own history.")
- new_history = import_history.copy( target_user=trans.user )
- new_history.name = "imported: "+new_history.name
+ return trans.show_error_message( "You cannot import your own history." )
+ new_history = import_history.copy( target_user=user )
+ new_history.name = "imported: " + new_history.name
new_history.user_id = user.id
galaxy_session = trans.get_galaxy_session()
try:
- association = trans.app.model.GalaxySessionToHistoryAssociation.filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
+ association = trans.app.model.GalaxySessionToHistoryAssociation \
+ .filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
new_history.flush()
if not user_history.datasets:
trans.set_history( new_history )
- trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) )
return trans.show_ok_message( """
History "%s" has been imported. Click <a href="%s">here</a>
to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
elif not user_history.datasets or confirm:
new_history = import_history.copy()
- new_history.name = "imported: "+new_history.name
+ new_history.name = "imported: " + new_history.name
new_history.user_id = None
galaxy_session = trans.get_galaxy_session()
try:
- association = trans.app.model.GalaxySessionToHistoryAssociation.filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
+ association = trans.app.model.GalaxySessionToHistoryAssociation \
+ .filter_by( session_id=galaxy_session.id, history_id=new_history.id ).first()
except:
association = None
new_history.add_galaxy_session( galaxy_session, association=association )
new_history.flush()
trans.set_history( new_history )
- trans.log_event( "History imported, id: %s, name: '%s': " % (str(new_history.id) , new_history.name ) )
return trans.show_ok_message( """
History "%s" has been imported. Click <a href="%s">here</a>
to begin.""" % ( new_history.name, web.url_for( '/' ) ) )
@@ -262,106 +285,33 @@
def share( self, trans, id=None, email="", **kwd ):
# If a history contains both datasets that can be shared and others that cannot be shared with the desired user,
# then the entire history is shared, and the protected datasets will be visible, but inaccessible ( greyed out )
- # in the shared history
+ # in the cloned history
params = util.Params( kwd )
- action = params.get( 'action', None )
- if action == "no_share":
- trans.response.send_redirect( url_for( controller='root', action='history_options' ) )
- if not id:
- id = trans.get_history().id
- id = util.listify( id )
- send_to_err = ""
- histories = []
- for hid in id:
- histories.append( trans.app.model.History.get( hid ) )
+ user = trans.get_user()
if not email:
- return trans.fill_template( "/history/share.mako", histories=histories, email=email, send_to_err=send_to_err )
- user = trans.get_user()
- send_to_users = []
- for email_address in util.listify( email ):
- email_address = email_address.strip()
- if email_address:
- if email_address == user.email:
- send_to_err += "You can't send histories to yourself. "
- else:
- send_to_user = trans.app.model.User.filter( trans.app.model.User.table.c.email==email_address ).first()
- if send_to_user:
- send_to_users.append( send_to_user )
- else:
- send_to_err += "%s is not a valid Galaxy user. " % email_address
+ if not id:
+ # Default to the current history
+ id = trans.security.encode_id( trans.history.id )
+ id = util.listify( id )
+ send_to_err = ""
+ histories = []
+ for history_id in id:
+ histories.append( get_history( trans, history_id ) )
+ return trans.fill_template( "/history/share.mako",
+ histories=histories,
+ email=email,
+ send_to_err=send_to_err )
+ histories, send_to_users, send_to_err = self._get_histories_and_users( trans, user, id, email )
if not send_to_users:
if not send_to_err:
send_to_err += "%s is not a valid Galaxy user. " % email
- return trans.fill_template( "/history/share.mako", histories=histories, email=email, send_to_err=send_to_err )
- if params.get( 'share_proceed_button', False ) and action == 'share':
- # We need to filter out all histories that cannot be shared
- filtered_histories = {}
- for history in histories:
- for send_to_user in send_to_users:
- # Only deal with datasets that have not been purged
- for hda in history.activatable_datasets:
- # The history can be shared if it contains at least 1 public dataset or 1 dataset that the
- # other user can access. Inaccessible datasets contained in the history will be displayed
- # in the shared history, but "greyed out", so they cannot be viewed or used.
- if trans.app.security_agent.dataset_is_public( hda.dataset ) or \
- trans.app.security_agent.allow_action( send_to_user,
- trans.app.security_agent.permitted_actions.DATASET_ACCESS,
- dataset=hda ):
- if send_to_user in filtered_histories:
- filtered_histories[ send_to_user ].append( history )
- else:
- filtered_histories[ send_to_user ] = [ history ]
- break
- return self._share_histories( trans, user, send_to_users, send_to_err, filtered_histories=filtered_histories )
- elif params.get( 'history_share_btn', False ) or action != 'share':
- # The user is attempting to share histories whose datasets cannot all be accessed by other users. In this case,
- # the user sharing the histories can:
- # 1) action=='public': chose to make the datasets public if he is permitted to do so
- # 2) action=='private': automatically create a new "sharing role" allowing protected
- # datasets to be accessed only by the desired users
- # 3) action=='share': share only what can be shared when no permissions are changed - this case is handled above
- # 4) action=='no_share': Do not share anything - this case is handled above.
- can_change = {}
- cannot_change = {}
- no_change_needed = {}
- for history in histories:
- # Only deal with datasets that have not been purged
- for hda in history.activatable_datasets:
- if trans.app.security_agent.dataset_is_public( hda.dataset ):
- if history not in no_change_needed:
- no_change_needed[ history ] = [ hda ]
- else:
- no_change_needed[ history ].append( hda )
- elif not trans.app.security_agent.allow_action( send_to_user,
- trans.app.security_agent.permitted_actions.DATASET_ACCESS,
- dataset=hda ):
- # The user with which we are sharing the history does not have access permission on the current dataset
- if trans.app.security_agent.allow_action( user,
- trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS,
- dataset=hda ) and not hda.dataset.library_associations:
- # The current user has authority to change permissions on the current dataset because
- # they have permission to manage permissions on the dataset and the dataset is not associated
- # with a library.
- if action == "private":
- trans.app.security_agent.privately_share_dataset( hda.dataset, users=[ user, send_to_user ] )
- elif action == "public":
- trans.app.security_agent.make_dataset_public( hda.dataset )
- elif history not in can_change:
- # Build the set of histories / datasets on which the current user has authority
- # to "manage permissions". This is used in /history/share.mako
- can_change[ history ] = [ hda ]
- else:
- can_change[ history ].append( hda )
- else:
- if action in [ "private", "public" ]:
- # Don't change stuff that the user doesn't have permission to change
- continue
- elif history not in cannot_change:
- # Build the set of histories / datasets on which the current user does
- # not have authority to "manage permissions". This is used in /history/share.mako
- cannot_change[ history ] = [ hda ]
- else:
- cannot_change[ history ].append( hda )
+ return trans.fill_template( "/history/share.mako",
+ histories=histories,
+ email=email,
+ send_to_err=send_to_err )
+ if params.get( 'share_button', False ):
+ can_change, cannot_change, no_change_needed = \
+ self._populate_restricted( trans, user, histories, send_to_users, None )
if can_change or cannot_change:
return trans.fill_template( "/history/share.mako",
histories=histories,
@@ -370,65 +320,253 @@
can_change=can_change,
cannot_change=cannot_change,
no_change_needed=no_change_needed )
- return self._share_histories( trans, user, send_to_users, send_to_err, histories=histories )
+ if no_change_needed:
+ return self._share_histories( trans, user, send_to_err, histories=no_change_needed )
+ elif not send_to_err:
+ # User seems to be sharing an empty history
+ send_to_err = "You cannot share an empty history. "
return trans.fill_template( "/history/share.mako", histories=histories, email=email, send_to_err=send_to_err )
- def _share_histories( self, trans, user, send_to_users, send_to_err, histories=[], filtered_histories={} ):
+ @web.expose
+ @web.require_login( "share restricted histories with other users" )
+ def share_restricted( self, trans, id=None, email="", **kwd ):
+ action = kwd[ 'action' ]
+ if action == "no_share":
+ trans.response.send_redirect( url_for( controller='root', action='history_options' ) )
+ user = trans.get_user()
+ histories, send_to_users, send_to_err = self._get_histories_and_users( trans, user, id, email )
+ send_to_err = ''
+ can_change, cannot_change, no_change_needed = \
+ self._populate_restricted( trans, user, histories, send_to_users, action )
+ # Now that we've populated the can_change, cannot_change, and no_change_needed dictionaries,
+ # we'll populate the histories_for_sharing dictionary from each of them.
+ histories_for_sharing = {}
+ if no_change_needed:
+ # Don't need to change anything in cannot_change, so populate as is
+ histories_for_sharing, send_to_err = \
+ self._populate( trans, histories_for_sharing, no_change_needed, send_to_err )
+ if cannot_change:
+ # Can't change anything in cannot_change, so populate as is
+ histories_for_sharing, send_to_err = \
+ self._populate( trans, histories_for_sharing, cannot_change, send_to_err )
+ # The action here is either 'public' or 'private', so we'll continue to populate the
+ # histories_for_sharing dictionary from the can_change dictionary.
+ for send_to_user, history_dict in can_change.items():
+ for history in history_dict:
+ # Make sure the current history has not already been shared with the current send_to_user
+ if trans.app.model.HistoryUserShareAssociation \
+ .filter( and_( trans.app.model.HistoryUserShareAssociation.table.c.user_id == send_to_user.id,
+ trans.app.model.HistoryUserShareAssociation.table.c.history_id == history.id ) ) \
+ .count() > 0:
+ send_to_err += "History (%s) already shared with user (%s)" % ( history.name, send_to_user.email )
+ else:
+ # Only deal with datasets that have not been purged
+ for hda in history.activatable_datasets:
+ # If the current dataset is not public, we may need to perform an action on it to
+ # make it accessible by the other user.
+ if not trans.app.security_agent.allow_action( send_to_user,
+ trans.app.security_agent.permitted_actions.DATASET_ACCESS,
+ dataset=hda ):
+ # The user with which we are sharing the history does not have access permission on the current dataset
+ if trans.app.security_agent.allow_action( user,
+ trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS,
+ dataset=hda ) and not hda.dataset.library_associations:
+ # The current user has authority to change permissions on the current dataset because
+ # they have permission to manage permissions on the dataset and the dataset is not associated
+ # with a library.
+ if action == "private":
+ trans.app.security_agent.privately_share_dataset( hda.dataset, users=[ user, send_to_user ] )
+ elif action == "public":
+ trans.app.security_agent.make_dataset_public( hda.dataset )
+ # Populate histories_for_sharing with the history after performing any requested actions on
+ # it's datasets to make them accessible by the other user.
+ if send_to_user not in histories_for_sharing:
+ histories_for_sharing[ send_to_user ] = [ history ]
+ elif history not in histories_for_sharing[ send_to_user ]:
+ histories_for_sharing[ send_to_user ].append( history )
+ return self._share_histories( trans, user, send_to_err, histories=histories_for_sharing )
+ def _get_histories_and_users( self, trans, user, id, email ):
+ if not id:
+ # Default to the current history
+ id = trans.security.encode_id( trans.history.id )
+ id = util.listify( id )
+ send_to_err = ""
+ histories = []
+ for history_id in id:
+ histories.append( get_history( trans, history_id ) )
+ send_to_users = []
+ for email_address in util.listify( email ):
+ email_address = email_address.strip()
+ if email_address:
+ if email_address == user.email:
+ send_to_err += "You cannot send histories to yourself. "
+ else:
+ send_to_user = trans.app.model.User.filter( and_( trans.app.model.User.table.c.email==email_address,
+ trans.app.model.User.table.c.deleted==False ) ).first()
+ if send_to_user:
+ send_to_users.append( send_to_user )
+ else:
+ send_to_err += "%s is not a valid Galaxy user. " % email_address
+ return histories, send_to_users, send_to_err
+ def _populate( self, trans, histories_for_sharing, other, send_to_err ):
+ # this method will populate the histories_for_sharing dictionary with the users and
+ # histories in other, eliminating histories that have already been shared with the
+ # associated user. No security checking on datasets is performed.
+ # If not empty, the histories_for_sharing dictionary looks like:
+ # { userA: [ historyX, historyY ], userB: [ historyY ] }
+ # other looks like:
+ # ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
+ for send_to_user, history_dict in other.items():
+ for history in history_dict:
+ # Make sure the current history has not already been shared with the current send_to_user
+ if trans.app.model.HistoryUserShareAssociation \
+ .filter( and_( trans.app.model.HistoryUserShareAssociation.table.c.user_id == send_to_user.id,
+ trans.app.model.HistoryUserShareAssociation.table.c.history_id == history.id ) ) \
+ .count() > 0:
+ send_to_err += "History (%s) already shared with user (%s)" % ( history.name, send_to_user.email )
+ else:
+ # Build the dict that will be used for sharing
+ if send_to_user not in histories_for_sharing:
+ histories_for_sharing[ send_to_user ] = [ history ]
+ elif history not in histories_for_sharing[ send_to_user ]:
+ histories_for_sharing[ send_to_user ].append( history )
+ return histories_for_sharing, send_to_err
+ def _populate_restricted( self, trans, user, histories, send_to_users, action ):
+ # The user may be attempting to share histories whose datasets cannot all be accessed by other users.
+ # If this is the case, the user sharing the histories can:
+ # 1) action=='public': choose to make the datasets public if he is permitted to do so
+ # 2) action=='private': automatically create a new "sharing role" allowing protected
+ # datasets to be accessed only by the desired users
+ # 3) action=='share_anyway': share only what can be shared when no permissions are changed
+ # 4) action=='no_share': Do not share anything
+ # In addition, the user may be sharing a history with a user with which the history was already shared
+ # and it will not be shared twice.
+ # This method will populate the can_change, cannot_change and no_change_needed dictionaries.
+ can_change = {}
+ cannot_change = {}
+ no_change_needed = {}
+ for history in histories:
+ for send_to_user in send_to_users:
+ # Make sure the current history has not already been shared with the current send_to_user
+ if trans.app.model.HistoryUserShareAssociation \
+ .filter( and_( trans.app.model.HistoryUserShareAssociation.table.c.user_id == send_to_user.id,
+ trans.app.model.HistoryUserShareAssociation.table.c.history_id == history.id ) ) \
+ .count() > 0:
+ send_to_err += "History (%s) already shared with user (%s)" % ( history.name, send_to_user.email )
+ else:
+ # Only deal with datasets that have not been purged
+ for hda in history.activatable_datasets:
+ if trans.app.security_agent.dataset_is_public( hda.dataset ):
+ # Build the dict that will show the user what doesn't need to be changed
+ if send_to_user not in no_change_needed:
+ no_change_needed[ send_to_user ] = {}
+ if history not in no_change_needed[ send_to_user ]:
+ no_change_needed[ send_to_user ][ history ] = [ hda ]
+ else:
+ no_change_needed[ send_to_user ][ history ].append( hda )
+ elif not trans.app.security_agent.allow_action( send_to_user,
+ trans.app.security_agent.permitted_actions.DATASET_ACCESS,
+ dataset=hda ):
+ # The user with which we are sharing the history does not have access permission on the current dataset
+ if trans.app.security_agent.allow_action( user,
+ trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS,
+ dataset=hda ) and not hda.dataset.library_associations:
+ # The current user has authority to change permissions on the current dataset because
+ # they have permission to manage permissions on the dataset and the dataset is not associated
+ # with a library.
+ if send_to_user not in can_change:
+ # Build the set of histories / datasets on which the current user has authority
+ # to "manage permissions".
+ can_change[ send_to_user ] = {}
+ if history not in can_change[ send_to_user ]:
+ can_change[ send_to_user ][ history ] = [ hda ]
+ else:
+ can_change[ send_to_user ][ history ].append( hda )
+ else:
+ if action in [ "private", "public" ]:
+ # Don't change stuff that the user doesn't have permission to change
+ continue
+ #elif send_to_user not in cannot_change:
+ if send_to_user not in cannot_change:
+ # Build the set of histories / datasets on which the current user does
+ # not have authority to "manage permissions".
+ cannot_change[ send_to_user ] = {}
+ if history not in cannot_change[ send_to_user ]:
+ cannot_change[ send_to_user ][ history ] = [ hda ]
+ else:
+ cannot_change[ send_to_user ][ history ].append( hda )
+ return can_change, cannot_change, no_change_needed
+ def _share_histories( self, trans, user, send_to_err, histories={} ):
+ # histories looks like: { userA: [ historyX, historyY ], userB: [ historyY ] }
msg = ""
- if not send_to_users:
- msg = "No users have been specified with which to share histories"
sent_to_emails = []
- for sent_to_user in send_to_users:
- sent_to_emails.append( sent_to_user.email )
+ for send_to_user in histories.keys():
+ sent_to_emails.append( send_to_user.email )
emails = ",".join( e for e in sent_to_emails )
- if not histories and not filtered_histories:
- msg = "No histories can be sent to (%s) without changing dataset permissions associating a sharing role with them" % emails
- elif histories:
- history_names = []
- for history in histories:
- history_names.append( history.name )
- for send_to_user in send_to_users:
- new_history = history.copy( target_user=send_to_user )
- new_history.name = history.name + " from " + user.email
- new_history.user_id = send_to_user.id
- self.app.model.flush()
- msg = "Histories (%s) have been shared with: %s. " % ( ",".join( history_names ), emails )
- elif filtered_histories:
- # filtered_histories is a dictionary like: { user: [ history, history ], user: [ history ] }
- for send_to_user, histories in filtered_histories.items():
- history_names = []
- for history in histories:
- history_names.append( history.name )
- new_history = history.copy( target_user=send_to_user )
- new_history.name = history.name + " from " + user.email
- new_history.user_id = send_to_user.id
- self.app.model.flush()
- msg += "Histories (%s) have been shared with: %s. " % ( ",".join( history_names ), send_to_user.email )
+ if not histories:
+ send_to_err += "No users have been specified or no histories can be sent without changing permissions or associating a sharing role. "
+ else:
+ for send_to_user, send_to_user_histories in histories.items():
+ shared_histories = []
+ for history in send_to_user_histories:
+ share = trans.app.model.HistoryUserShareAssociation()
+ share.history = history
+ share.user = send_to_user
+ session = trans.sa_session
+ session.save_or_update( share )
+ session.flush()
+ if history not in shared_histories:
+ shared_histories.append( history )
if send_to_err:
msg += send_to_err
- return trans.show_message( msg )
+ return self.sharing( trans, histories=shared_histories, msg=msg )
+ @web.expose
+ @web.require_login( "share histories with other users" )
+ def sharing( self, trans, histories=[], id=None, **kwd ):
+ # histories looks like: [ historyX, historyY ]
+ params = util.Params( kwd )
+ msg = util.restore_text ( params.get( 'msg', '' ) )
+ if id:
+ histories = [ get_history( trans, id ) ]
+ for history in histories:
+ if params.get( 'enable_import_via_link', False ):
+ history.importable = True
+ history.flush()
+ elif params.get( 'disable_import_via_link', False ):
+ history.importable = False
+ history.flush()
+ elif params.get( 'unshare_user', False ):
+ user = 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' )
+ association = trans.app.model.HistoryUserShareAssociation.filter_by( user=user, history=history ).one()
+ association.delete()
+ association.flush()
+ if not id:
+ shared_msg = "History (%s) now shared with: %d users. " % ( history.name, len( history.users_shared_with ) )
+ msg = '%s%s' % ( shared_msg, msg )
+ return trans.fill_template( 'history/sharing.mako', histories=histories, msg=msg, messagetype='done' )
@web.expose
@web.require_login( "rename histories" )
def rename( self, trans, id=None, name=None, **kwd ):
user = trans.get_user()
- if not isinstance( id, list ):
- if id != None:
- id = [ id ]
- if not isinstance( name, list ):
- if name != None:
- name = [ name ]
+ if not id:
+ # Default to the current history
+ history = trans.get_history()
+ if not history.user:
+ return trans.show_error_message( "You must save your history before renaming it." )
+ id = trans.security.encode_id( history.id )
+ id = util.listify( id )
+ name = util.listify( name )
histories = []
cur_names = []
- if not id:
- if not trans.get_history().user:
- return trans.show_error_message( "You must save your history before renaming it." )
- id = [trans.get_history().id]
for history_id in id:
- history = trans.app.model.History.get( history_id )
+ history = get_history( trans, history_id )
if history and history.user_id == user.id:
- histories.append(history)
- cur_names.append(history.name)
- if not name or len(histories)!=len(name):
- return trans.fill_template( "/history/rename.mako",histories=histories )
+ histories.append( history )
+ cur_names.append( history.name )
+ if not name or len( histories ) != len( name ):
+ return trans.fill_template( "/history/rename.mako", histories=histories )
change_msg = ""
for i in range(len(histories)):
if histories[i].user_id == user.id:
@@ -445,3 +583,38 @@
else:
change_msg = change_msg + "<p>History: "+cur_names[i]+" does not appear to belong to you.</p>"
return trans.show_message( "<p>%s" % change_msg, refresh_frames=['history'] )
+ @web.expose
+ @web.require_login( "clone shared Galaxy history" )
+ def clone( self, trans, id ):
+ history = get_history( trans, id, check_ownership=False )
+ user = trans.get_user()
+ if history.user == user:
+ owner = True
+ else:
+ if trans.sa_session.query( trans.app.model.HistoryUserShareAssociation ) \
+ .filter_by( user=user, history=history ).count() == 0:
+ return trans.show_error_message( "The history you are attempting to clone is not owned by you or shared with you. " )
+ owner = False
+ name = "Clone of '%s'" % history.name
+ if not owner:
+ name += " shared by '%s'" % history.user.email
+ new_history = history.copy( name=name, target_user=user )
+ # Render the list view
+ return trans.show_ok_message( 'Clone with name "%s" is now included in your list of stored histories.' % new_history.name )
+
+## ---- Utility methods -------------------------------------------------------
+
+def get_history( trans, id, check_ownership=True ):
+ """Get a History from the database by id, verifying ownership."""
+ # Load history from database
+ id = trans.security.decode_id( id )
+ history = trans.sa_session.query( model.History ).get( id )
+ if not history:
+ err+msg( "History not found" )
+ # Verify ownership
+ user = trans.get_user()
+ if not user:
+ error( "Must be logged in to manage histories" )
+ if check_ownership and not( history.user == user ):
+ error( "History is not owned by current user" )
+ return history
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/controllers/root.py
--- a/lib/galaxy/web/controllers/root.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/controllers/root.py Mon Jun 29 16:30:16 2009 -0400
@@ -50,19 +50,18 @@
@web.expose
def history( self, trans, as_xml=False, show_deleted=False ):
"""
- Display the current history, creating a new history if neccesary.
-
+ Display the current history, creating a new history if necessary.
NOTE: No longer accepts "id" or "template" options for security reasons.
"""
- history = trans.get_history()
if trans.app.config.require_login and not trans.user:
return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
+ history = trans.get_history( create=True )
if as_xml:
trans.response.set_content_type('text/xml')
return trans.fill_template_mako( "root/history_as_xml.mako", history=history, show_deleted=util.string_as_bool( show_deleted ) )
else:
template = "root/history.mako"
- return trans.fill_template( "root/history.mako", history = history, show_deleted = util.string_as_bool( show_deleted ) )
+ return trans.fill_template( "root/history.mako", history=history, show_deleted=util.string_as_bool( show_deleted ) )
@web.expose
def dataset_state ( self, trans, id=None, stamp=None ):
@@ -350,9 +349,10 @@
@web.expose
def history_options( self, trans ):
- """Displays a list of history related actions"""
+ """Displays a list of history related actions"""
return trans.fill_template( "/history/options.mako",
- user = trans.get_user(), history = trans.get_history() )
+ user=trans.get_user(),
+ history=trans.get_history( create=True ) )
@web.expose
def history_delete( self, trans, id ):
"""
@@ -421,7 +421,7 @@
@web.expose
def history_new( self, trans, name=None ):
trans.new_history( name=name )
- trans.log_event( "Created new History, id: %s." % str(trans.get_history().id) )
+ trans.log_event( "Created new History, id: %s." % str(trans.history.id) )
return trans.show_message( "New history created", refresh_frames = ['history'] )
@web.expose
def history_add_to( self, trans, history_id=None, file_data=None, name="Data Added to History",info=None,ext="txt",dbkey="?",copy_access_from=None,**kwd ):
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/controllers/user.py
--- a/lib/galaxy/web/controllers/user.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/controllers/user.py Mon Jun 29 16:30:16 2009 -0400
@@ -81,6 +81,7 @@
@web.expose
def login( self, trans, email='', password='' ):
+ log.debug( "###IN login, email:%s, password: %s" % ( email, password ))
email_error = password_error = None
# Attempt login
if trans.app.config.require_login:
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/controllers/workflow.py
--- a/lib/galaxy/web/controllers/workflow.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/controllers/workflow.py Mon Jun 29 16:30:16 2009 -0400
@@ -129,7 +129,7 @@
if stored.importable == False:
error( "The owner of this workflow has disabled imports via this link" )
elif stored.user == trans.user:
- error( "You are already the ownder of this workflow, can't import" )
+ error( "You are already the owner of this workflow, can't import" )
elif stored.deleted:
error( "This workflow has been deleted, can't import" )
elif session.query( model.StoredWorkflowUserShareAssociation ) \
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/framework/__init__.py Mon Jun 29 16:30:16 2009 -0400
@@ -180,7 +180,7 @@
except:
event.message = message
try:
- event.history = self.history
+ event.history = self.get_history()
except:
event.history = None
try:
@@ -337,11 +337,11 @@
remote_host = self.request.remote_host,
remote_addr = self.request.remote_addr,
referer = self.request.headers.get( 'Referer', None ) )
- # Invalidated an existing sesssion for some reason, keep track
if prev_galaxy_session:
+ # Invalidated an existing session for some reason, keep track
galaxy_session.prev_session_id = prev_galaxy_session.id
- # The new session should be immediately associated with a user
if user_for_new_session:
+ # The new session should be associated with the user
galaxy_session.user = user_for_new_session
return galaxy_session
def __get_or_create_remote_user( self, remote_user_email ):
@@ -350,12 +350,23 @@
"""
# remote_user middleware ensures HTTP_REMOTE_USER exists
user = self.app.model.User.filter( self.app.model.User.table.c.email==remote_user_email ).first()
- if user is None:
+ if user:
+ # GVK: June 29, 2009 - This is to correct the behavior of a previous bug where a private
+ # role and default user / history permissions were not set for remote users. When a
+ # remote user authenticates, we'll look for this information, and if missing, create it.
+ if not self.app.security_agent.get_private_user_role( user ):
+ self.app.security_agent.create_private_user_role( user )
+ if not user.default_permissions:
+ self.app.security_agent.user_set_default_permissions( user, history=True, dataset=True )
+ elif user is None:
random.seed()
user = self.app.model.User( email=remote_user_email )
user.set_password_cleartext( ''.join( random.sample( string.letters + string.digits, 12 ) ) )
user.external = True
user.flush()
+ self.app.security_agent.create_private_user_role( user )
+ # We set default user permissions, before we log in and set the default history permissions
+ self.app.security_agent.user_set_default_permissions( user )
#self.log_event( "Automatically created account '%s'", user.email )
elif user.deleted:
return self.show_error_message( "Your account is no longer valid, contact your Galaxy administrator to activate your account." )
@@ -365,7 +376,6 @@
Update the session cookie to match the current session.
"""
self.set_cookie( self.security.encode_session_key( self.galaxy_session.session_key ), name=name )
-
def handle_user_login( self, user ):
"""
Login a new user (possibly newly created)
@@ -374,24 +384,39 @@
- if old session had a history and it was not associated with a user, associate it with the new session,
otherwise associate the current session's history with the user
"""
+ # Set the previous session
prev_galaxy_session = self.galaxy_session
prev_galaxy_session.is_valid = False
+ # Define a new current_session
self.galaxy_session = self.__create_new_session( prev_galaxy_session, user )
- # If the session already had a history, we associate it with the new
- # session, but only if it does not belong to a different user.
- if prev_galaxy_session.current_history and \
- ( prev_galaxy_session.current_history.user == user or prev_galaxy_session.user is None ):
- history = prev_galaxy_session.current_history
- elif self.galaxy_session.current_history:
- history = self.galaxy_session.current_history
- else:
- history = self.history
+ # Associated the current user's last accessed history (if exists) with their new session
+ history = None
+ try:
+ users_last_session = user.galaxy_sessions[0]
+ last_accessed = True
+ except:
+ users_last_session = None
+ last_accessed = False
+ if users_last_session and users_last_session.current_history:
+ history = users_last_session.current_history
+ if not history:
+ if prev_galaxy_session.current_history:
+ if prev_galaxy_session.current_history.user is None or prev_galaxy_session.current_history.user == user:
+ # If the previous galaxy session had a history, associate it with the new
+ # session, but only if it didn't belong to a different user.
+ history = prev_galaxy_session.current_history
+ elif self.galaxy_session.current_history:
+ history = self.galaxy_session.current_history
+ else:
+ history = self.get_history( create=True )
if history not in self.galaxy_session.histories:
self.galaxy_session.add_history( history )
if history.user is None:
history.user = user
self.galaxy_session.current_history = history
- self.app.security_agent.history_set_default_permissions( history, dataset=True, bypass_manage_permission=True )
+ if not last_accessed:
+ # Only set default history permissions if current history is not from a previous session
+ self.app.security_agent.history_set_default_permissions( history, dataset=True, bypass_manage_permission=True )
self.sa_session.flush( [ prev_galaxy_session, self.galaxy_session, history ] )
# This method is not called from the Galaxy reports, so the cookie will always be galaxysession
self.__update_session_cookie( name='galaxysession' )
@@ -403,7 +428,7 @@
"""
prev_galaxy_session = self.galaxy_session
prev_galaxy_session.is_valid = False
- self.galaxy_session = self.__create_new_session( prev_galaxy_session, None )
+ self.galaxy_session = self.__create_new_session( prev_galaxy_session )
self.sa_session.flush( [ prev_galaxy_session, self.galaxy_session ] )
# This method is not called from the Galaxy reports, so the cookie will always be galaxysession
self.__update_session_cookie( name='galaxysession' )
@@ -416,16 +441,15 @@
def get_history( self, create=False ):
"""
- Load the current history.
-
- NOTE: It looks like create was being ignored for a long time, so this
- will currently *always* create a new history. This is wasteful
- though, and we should verify that callers are using the create
- flag correctly and fix.
+ Load the current history, creating a new one only if there is not
+ current history and we're told to create"
"""
history = self.galaxy_session.current_history
- if history is None:
- history = self.new_history()
+ if not history:
+ if util.string_as_bool( create ):
+ history = self.new_history()
+ else:
+ raise "get_history() returning None"
return history
def set_history( self, history ):
if history and not history.deleted:
@@ -557,7 +581,8 @@
the user (chromInfo in history).
"""
dbnames = list()
- datasets = self.app.model.HistoryDatasetAssociation.filter_by(deleted=False, history_id=self.history.id, extension="len").all()
+ datasets = self.app.model.HistoryDatasetAssociation \
+ .filter_by(deleted=False, history_id=self.history.id, extension="len").all()
if len(datasets) > 0:
dbnames.append( (util.dbnames.default_value, '--------- User Defined Builds ----------') )
for dataset in datasets:
@@ -569,7 +594,8 @@
"""
Returns the db_file dataset associated/needed by `dataset`, or `None`.
"""
- datasets = self.app.model.HistoryDatasetAssociation.filter_by(deleted=False, history_id=self.history.id, extension="len").all()
+ datasets = self.app.model.HistoryDatasetAssociation \
+ .filter_by(deleted=False, history_id=self.history.id, extension="len").all()
for ds in datasets:
if dbkey == ds.dbkey:
return ds
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/framework/helpers/grids.py
--- a/lib/galaxy/web/framework/helpers/grids.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/framework/helpers/grids.py Mon Jun 29 16:30:16 2009 -0400
@@ -3,7 +3,9 @@
from galaxy.web import url_for
-import sys
+import sys, logging
+
+log = logging.getLogger( __name__ )
class Grid( object ):
"""
@@ -12,6 +14,7 @@
title = ""
exposed = True
model_class = None
+ template = None
columns = []
standard_filters = []
default_filter = None
@@ -22,6 +25,7 @@
def __call__( self, trans, **kwargs ):
status = kwargs.get( 'status', None )
message = kwargs.get( 'message', None )
+ template = kwargs.get( 'template', None )
session = trans.sa_session
# Build initial query
query = self.build_initial_query( session )
@@ -70,8 +74,15 @@
if len(args) > 0:
new_kwargs.update( args[0] )
new_kwargs.update( kwargs )
+ # We need to encode item ids
+ if 'id' in new_kwargs:
+ id = new_kwargs[ 'id' ]
+ if isinstance( id, list ):
+ new_args[ 'id' ] = [ trans.security.encode_id( i ) for i in id ]
+ else:
+ new_kwargs[ 'id' ] = trans.security.encode_id( id )
return url_for( **new_kwargs )
- return trans.fill_template( "grid.mako",
+ return trans.fill_template( template,
grid=self,
query=query,
sort_key=sort_key,
diff -r b26e2ef8726c -r 533ae45c4440 lib/galaxy/web/security/__init__.py
--- a/lib/galaxy/web/security/__init__.py Fri Jun 26 09:22:31 2009 -0400
+++ b/lib/galaxy/web/security/__init__.py Mon Jun 29 16:30:16 2009 -0400
@@ -30,9 +30,7 @@
random_pool.stir()
return str( number.getRandomNumber( nbits, random_pool.get_bytes ) )
-
class SecurityHelper( object ):
- # TODO: checking if histories/datasets are owned by the current user) will be moved here.
def __init__( self, **config ):
self.id_secret = config['id_secret']
self.id_cipher = Blowfish.new( self.id_secret )
diff -r b26e2ef8726c -r 533ae45c4440 templates/grid.mako
--- a/templates/grid.mako Fri Jun 26 09:22:31 2009 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +0,0 @@
-<%inherit file="/base.mako"/>
-<%def name="title()">${grid.title}</%def>
-
-%if message:
- <p>
- <div class="${message_type}message transient-message">${message}</div>
- <div style="clear: both"></div>
- </p>
-%endif
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- <script type="text/javascript">
- ## TODO: generalize and move into galaxy.base.js
- $(document).ready(function() {
- $(".grid").each( function() {
- var grid = this;
- var checkboxes = $(this).find("input.grid-row-select-checkbox");
- var update = $(this).find( "span.grid-selected-count" );
- $(checkboxes).each( function() {
- $(this).change( function() {
- var n = $(checkboxes).filter("[checked]").size();
- update.text( n );
- });
- })
- });
- });
-
- ## Can this be moved into base.mako?
- %if refresh_frames:
- %if 'masthead' in refresh_frames:
- ## Refresh masthead == user changes (backward compatibility)
- if ( parent.user_changed ) {
- %if trans.user:
- parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} );
- %else:
- parent.user_changed( null, false );
- %endif
- }
- %endif
- %if 'history' in refresh_frames:
- if ( parent.frames && parent.frames.galaxy_history ) {
- parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}";
- if ( parent.force_right_panel ) {
- parent.force_right_panel( 'show' );
- }
- }
- %endif
- %if 'tools' in refresh_frames:
- if ( parent.frames && parent.frames.galaxy_tools ) {
- parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}";
- if ( parent.force_left_panel ) {
- parent.force_left_panel( 'show' );
- }
- }
- %endif
- %endif
- </script>
-</%def>
-
-<%def name="stylesheets()">
- <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
- <style>
- ## Not generic to all grids -- move to base?
- .count-box {
- min-width: 1.1em;
- padding: 5px;
- border-width: 1px;
- border-style: solid;
- text-align: center;
- display: inline-block;
- }
- </style>
-</%def>
-
-
-<div class="grid-header">
- <h2>${grid.title}</h2>
- <span class="title">Filter:</span>
- %for i, filter in enumerate( grid.standard_filters ):
- %if i > 0:
- <span>|</span>
- %endif
- <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
- %endfor
-</div>
-
-<form name="history_actions" action="${url()}" method="post" >
-
- <table class="grid">
- <thead>
- <tr>
- <th></th>
- %for column in grid.columns:
- %if column.visible:
- <%
- href = ""
- extra = ""
- if column.sortable:
- if sort_key == column.key:
- if sort_order == "asc":
- href = url( sort=( "-" + column.key ) )
- extra = "↓"
- else:
- href = url( sort=( column.key ) )
- extra = "↑"
- else:
- href = url( sort=column.key )
- %>
- <th \
- %if column.ncells > 1:
- colspan="${column.ncells}"
- %endif
- >
- %if href:
- <a href="${href}">${column.label}</a>
- %else:
- ${column.label}
- %endif
- <span>${extra}</span>
- </th>
- %endif
- %endfor
- <th></th>
-
- </tr>
- </thead>
-
- <tbody>
-
- %for i, item in enumerate( query ):
-
-
- <tr \
- %if current_item == item:
- class="current" \
- %endif
- >
-
- ## Item selection column
- <td style="width: 1.5em;"><input type="checkbox" name="id" value=${item.id} class="grid-row-select-checkbox"></input></td>
-
- ## Data columns
- %for column in grid.columns:
- %if column.visible:
- <%
- # Link
- if column.link and column.link( item ):
- href = url( **column.link( item ) )
- else:
- href = None
- # Value (coerced to list so we can loop)
- value = column.get_value( trans, grid, item )
- if column.ncells == 1:
- value = [ value ]
- %>
-
- %for cellnum, v in enumerate( value ):
- <%
- # Attach popup menu?
- if column.attach_popup and cellnum == 0:
- extra = '<a id="grid-%d-popup" class="popup-arrow" style="display: none;">▼</a>' % i
- else:
- extra = ""
- %>
-
- %if href:
- <td><a href="${href}">${v}</a> ${extra}</td>
- %else:
- <td >${v}${extra}</td>
- %endif
- </td>
- %endfor
- %endif
- %endfor
-
- ## Actions column
- <td>
- <div popupmenu="grid-${i}-popup">
-
- %for operation in grid.operations:
- %if operation.allowed( item ):
- <a class="action-button" href="${url( operation=operation.label, id=item.id )}">${operation.label}</a>
- %endif
- %endfor
-
- </div>
- </td>
-
- </tr>
-
- %endfor
-
- </tbody>
-
- <tfoot>
- <tr>
- <td></td>
- <td colspan="100">
- For <span class="grid-selected-count"></span> selected histories:
- %for operation in grid.operations:
- %if operation.allow_multiple:
- <input type="submit" name="operation" value="${operation.label}" class="action-button">
- %endif
- %endfor
-
- </td>
- </tr>
- </tfoot>
-
- </table>
-
- </form>
-
-
-
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/grid.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/history/grid.mako Mon Jun 29 16:30:16 2009 -0400
@@ -0,0 +1,193 @@
+<%inherit file="/base.mako"/>
+<%def name="title()">${grid.title}</%def>
+
+%if message:
+ <p>
+ <div class="${message_type}message transient-message">${message}</div>
+ <div style="clear: both"></div>
+ </p>
+%endif
+
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ ## TODO: generalize and move into galaxy.base.js
+ $(document).ready(function() {
+ $(".grid").each( function() {
+ var grid = this;
+ var checkboxes = $(this).find("input.grid-row-select-checkbox");
+ var update = $(this).find( "span.grid-selected-count" );
+ $(checkboxes).each( function() {
+ $(this).change( function() {
+ var n = $(checkboxes).filter("[checked]").size();
+ update.text( n );
+ });
+ })
+ });
+ });
+ ## Can this be moved into base.mako?
+ %if refresh_frames:
+ %if 'masthead' in refresh_frames:
+ ## Refresh masthead == user changes (backward compatibility)
+ if ( parent.user_changed ) {
+ %if trans.user:
+ parent.user_changed( "${trans.user.email}", ${int( app.config.is_admin_user( trans.user ) )} );
+ %else:
+ parent.user_changed( null, false );
+ %endif
+ }
+ %endif
+ %if 'history' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_history ) {
+ parent.frames.galaxy_history.location.href="${h.url_for( controller='root', action='history')}";
+ if ( parent.force_right_panel ) {
+ parent.force_right_panel( 'show' );
+ }
+ }
+ %endif
+ %if 'tools' in refresh_frames:
+ if ( parent.frames && parent.frames.galaxy_tools ) {
+ parent.frames.galaxy_tools.location.href="${h.url_for( controller='root', action='tool_menu')}";
+ if ( parent.force_left_panel ) {
+ parent.force_left_panel( 'show' );
+ }
+ }
+ %endif
+ %endif
+ </script>
+</%def>
+
+<%def name="stylesheets()">
+ <link href="${h.url_for('/static/style/base.css')}" rel="stylesheet" type="text/css" />
+ <style>
+ ## Not generic to all grids -- move to base?
+ .count-box {
+ min-width: 1.1em;
+ padding: 5px;
+ border-width: 1px;
+ border-style: solid;
+ text-align: center;
+ display: inline-block;
+ }
+ </style>
+</%def>
+
+<div class="grid-header">
+ <h2>${grid.title}</h2>
+ <span class="title">Filter:</span>
+ %for i, filter in enumerate( grid.standard_filters ):
+ %if i > 0:
+ <span>|</span>
+ %endif
+ <span class="filter"><a href="${url( filter.get_url_args() )}">${filter.label}</a></span>
+ %endfor
+</div>
+
+<form name="history_actions" action="${url()}" method="post" >
+ <table class="grid">
+ <thead>
+ <tr>
+ <th></th>
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ href = ""
+ extra = ""
+ if column.sortable:
+ if sort_key == column.key:
+ if sort_order == "asc":
+ href = url( sort=( "-" + column.key ) )
+ extra = "↓"
+ else:
+ href = url( sort=( column.key ) )
+ extra = "↑"
+ else:
+ href = url( sort=column.key )
+ %>
+ <th\
+ %if column.ncells > 1:
+ colspan="${column.ncells}"
+ %endif
+ >
+ %if href:
+ <a href="${href}">${column.label}</a>
+ %else:
+ ${column.label}
+ %endif
+ <span>${extra}</span>
+ </th>
+ %endif
+ %endfor
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ %for i, item in enumerate( query ):
+ <tr \
+ %if current_item == item:
+ class="current" \
+ %endif
+ >
+ ## Item selection column
+ <td style="width: 1.5em;">
+ <input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" />
+ </td>
+ ## Data columns
+ %for column in grid.columns:
+ %if column.visible:
+ <%
+ # Link
+ if column.link and column.link( item ):
+ href = url( **column.link( item ) )
+ else:
+ href = None
+ # Value (coerced to list so we can loop)
+ value = column.get_value( trans, grid, item )
+ if column.ncells == 1:
+ value = [ value ]
+ %>
+ %for cellnum, v in enumerate( value ):
+ <%
+ # Attach popup menu?
+ if column.attach_popup and cellnum == 0:
+ extra = '<a id="grid-%d-popup" class="popup-arrow" style="display: none;">▼</a>' % i
+ else:
+ extra = ""
+ %>
+ %if href:
+ <td><a href="${href}">${v}</a> ${extra}</td>
+ %else:
+ <td >${v}${extra}</td>
+ %endif
+ </td>
+ %endfor
+ %endif
+ %endfor
+ ## Actions column
+ <td>
+ <div popupmenu="grid-${i}-popup">
+ %for operation in grid.operations:
+ %if operation.allowed( item ):
+ <a class="action-button" href="${url( operation=operation.label, id=trans.security.encode_id( item.id ) )}">${operation.label}</a>
+ %endif
+ %endfor
+ </div>
+ </td>
+ </tr>
+ %endfor
+ </tbody>
+ <tfoot>
+ <tr>
+ <td></td>
+ <td colspan="100">
+ For <span class="grid-selected-count"></span> selected histories:
+ %for operation in grid.operations:
+ %if operation.allow_multiple:
+ <input type="submit" name="operation" value="${operation.label}" class="action-button">
+ %endif
+ %endfor
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+</form>
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/list_as_xml.mako
--- a/templates/history/list_as_xml.mako Fri Jun 26 09:22:31 2009 -0400
+++ b/templates/history/list_as_xml.mako Mon Jun 29 16:30:16 2009 -0400
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<history_ids>
%for i, history in enumerate( t.user.histories ):
- <data id="${history.id}" hid="${i+1}" num="${len(history.datasets)}" name="${history.name}" create="${history.create_time}" update="${history.update_time}" >
+ <data id="${trans.security.encode_id( history.id )}" hid="${i+1}" num="${len(history.datasets)}" name="${history.name}" create="${history.create_time}" update="${history.update_time}" >
</data>
%endfor
</history_ids>
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/list_shared.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/history/list_shared.mako Mon Jun 29 16:30:16 2009 -0400
@@ -0,0 +1,30 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+%if shared_by_others:
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>Name</th>
+ <th>Owner</th>
+ </tr>
+ %for i, association in enumerate( shared_by_others ):
+ <% history = association.history %>
+ <tr>
+ <td>
+ ${history.name}
+ <a id="shared-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
+ <div popupmenu="shared-${i}-popup">
+ <a class="action-button" href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ) )}">Clone</a>
+ </div>
+ </td>
+ <td>${history.user.email}</td>
+ </tr>
+ %endfor
+ </table>
+%else:
+ No histories have been shared with you.
+%endif
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/options.mako
--- a/templates/history/options.mako Fri Jun 26 09:22:31 2009 -0400
+++ b/templates/history/options.mako Mon Jun 29 16:30:16 2009 -0400
@@ -11,16 +11,22 @@
%endif
<ul>
-%if user:
- <li><a href="${h.url_for( controller='history', action='rename', id=history.id )}" target="galaxy_main">Rename</a> current history (stored as "${history.name}")</li>
- <li><a href="${h.url_for( controller='history', action='list')}" target="galaxy_main">List</a> previously stored histories</li>
- %if len( history.active_datasets ) > 0:
- <li><a href="${h.url_for( controller='root', action='history_new' )}">Create</a> a new empty history</li>
+ %if user:
+ <li><a href="${h.url_for( controller='history', action='list')}" target="galaxy_main">List</a> previously stored histories</li>
+ %if len( history.active_datasets ) > 0:
+ <li><a href="${h.url_for( controller='root', action='history_new' )}">Create</a> a new empty history</li>
+ <li><a href="${h.url_for( controller='workflow', action='build_from_current_history' )}">Construct workflow</a> from current history</li>
+ <li><a href="${h.url_for( controller='history', action='clone', id=trans.security.encode_id( history.id ) )}">Clone</a> current history</li>
+ %endif
+ <li><a href="${h.url_for( controller='history', action='share' )}" target="galaxy_main">Share</a> current history</div>
+ <li><a href="${h.url_for( action='history_set_default_permissions' )}">Change default permissions</a> for current history</li>
%endif
- <li><a href="${h.url_for( controller='workflow', action='build_from_current_history' )}">Construct workflow</a> from the current history</li>
- <li><a href="${h.url_for( controller='history', action='share' )}" target="galaxy_main">Share</a> current history</div>
- <li><a href="${h.url_for( action='history_set_default_permissions' )}">Change default permissions</a> for the current history</li>
-%endif
- <li><a href="${h.url_for( controller='root', action='history', show_deleted=True)}" target="galaxy_history">Show deleted</a> datasets in history</li>
+ %if len( history.activatable_datasets ) > 0:
+ <li><a href="${h.url_for( controller='root', action='history', show_deleted=True)}" target="galaxy_history">Show deleted</a> datasets in current history</li>
+ %endif
+ <li><a href="${h.url_for( controller='history', action='rename', id=trans.security.encode_id( history.id ) )}" target="galaxy_main">Rename</a> current history (stored as "${history.name}")</li>
<li><a href="${h.url_for( controller='history', action='delete_current' )}" confirm="Are you sure you want to delete the current history?">Delete</a> current history</div>
+ %if user and user.histories_shared_by_others:
+ <li><a href="${h.url_for( controller='history', action='list_shared')}" target="galaxy_main">List</a> histories shared with you by others</li>
+ %endif
</ul>
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/permissions.mako
--- a/templates/history/permissions.mako Fri Jun 26 09:22:31 2009 -0400
+++ b/templates/history/permissions.mako Mon Jun 29 16:30:16 2009 -0400
@@ -3,5 +3,6 @@
<%namespace file="/dataset/security_common.mako" import="render_permission_form" />
%if trans.user:
- ${render_permission_form( trans.history, trans.history.name, h.url_for(), trans.user.all_roles() )}
+ <% history = trans.get_history() %>
+ ${render_permission_form( history, history.name, h.url_for(), trans.user.all_roles() )}
%endif
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/rename.mako
--- a/templates/history/rename.mako Fri Jun 26 09:22:31 2009 -0400
+++ b/templates/history/rename.mako Mon Jun 29 16:30:16 2009 -0400
@@ -11,7 +11,7 @@
<tr>
<td>
<div class="form-row">
- <input type="hidden" name="id" value="${history.id}">
+ <input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
<label>${_('Current Name')}</label>
<div style="float: left; width: 250px; margin-right: 10px;">
${history.name}
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/share.mako
--- a/templates/history/share.mako Fri Jun 26 09:22:31 2009 -0400
+++ b/templates/history/share.mako Mon Jun 29 16:30:16 2009 -0400
@@ -5,14 +5,16 @@
<div class="toolForm">
<div class="toolFormTitle">Share ${len( histories)} histories</div>
<div class="toolFormBody">
- %if not can_change and not cannot_change:
- <form action="${h.url_for( controller="history", action='share' )}" method="post" >
+ %if not can_change and not cannot_change and not no_change_needed:
+ ## We are sharing histories that contain only public datasets
+ <form name='share' id='share' action="${h.url_for( controller="history", action='share' )}" method="post" >
%for history in histories:
+ <input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
<div class="toolForm">
<div class="form-row">
<label>${_('History Name:')}</label>
<div style="float: left; width: 250px; margin-right: 10px;">
- ${history.name}<input type="hidden" name="id" value="${history.id}">
+ ${history.name}
</div>
</div>
<div style="clear: both"></div>
@@ -27,15 +29,7 @@
</td>
</div>
</div>
- ## TODO: this feature is not currently working
- ##<div style="clear: both"></div>
- ##<div class="form-row">
- ## <label>${_('Share Link')}</label>
- ## <div style="float: left; width: 250px; margin-right: 10px;">
- ## <a href="${h.url_for( controller='history', action='imp', id=trans.security.encode_id(history.id) )}">${_('copy link to share')}</a>
- ## </div>
- ##</div>
- ##<div style="clear: both"></div>
+ <div style="clear: both"></div>
<p/>
</div>
%endfor
@@ -58,15 +52,17 @@
%endif
<div style="clear: both"></div>
<div class="form-row">
- <input type="submit" name="history_share_btn" value="Submit">
+ <input type="submit" name="share_button" value="Submit">
</div>
</form>
%else:
- <form action="${h.url_for( controller='history', action='share' )}" method="post">
+ ## We are sharing restricted histories
+ <form name='share_restricted' id=share_restricted' action="${h.url_for( controller='history', action='share_restricted' )}" method="post">
+ ## Needed for rebuilding dicts
+ <input type="hidden" name="email" value="${email}" size="40">
%for history in histories:
- <input type="hidden" name="id" value="${history.id}">
+ <input type="hidden" name="id" value="${trans.security.encode_id( history.id )}">
%endfor
- <input type="hidden" name="email" value="${email}">
%if no_change_needed:
<div style="clear: both"></div>
<div class="form-row">
@@ -74,7 +70,29 @@
The following datasets can be shared with ${email} with no changes
</div>
</div>
- %for history, hdas in no_change_needed.items():
+ ## no_change_needed looks like:
+ ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
+ <%
+ # TODO: move generation of these unique dictionaries to the history controller
+ # Build the list of unique histories and datasets
+ unique_stuff = {}
+ %>
+ %for user, history_dict in no_change_needed.items():
+ %for history, hdas in history_dict.items():
+ <%
+ if history in unique_stuff:
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ else:
+ unique_stuff[ history ] = []
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ %>
+ %endfor
+ %endfor
+ %for history, hdas in unique_stuff.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -97,7 +115,29 @@
The following datasets can be shared with ${email} by updating their permissions
</div>
</div>
- %for history, hdas in can_change.items():
+ ## can_change looks like:
+ ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
+ <%
+ # TODO: move generation of these unique dictionaries to the history controller
+ # Build the list of unique histories and datasets
+ unique_stuff = {}
+ %>
+ %for user, history_dict in can_change.items():
+ %for history, hdas in history_dict.items():
+ <%
+ if history in unique_stuff:
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ else:
+ unique_stuff[ history ] = []
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ %>
+ %endfor
+ %endfor
+ %for history, hdas in unique_stuff.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -121,7 +161,29 @@
change the permissions on them
</div>
</div>
- %for history, hdas in cannot_change.items():
+ ## cannot_change looks like:
+ ## { userA: {historyX : [hda, hda], historyY : [hda]}, userB: {historyY : [hda]} }
+ <%
+ # TODO: move generation of these unique dictionaries to the history controller
+ # Build the list of unique histories and datasets
+ unique_stuff = {}
+ %>
+ %for user, history_dict in can_change.items():
+ %for history, hdas in history_dict.items():
+ <%
+ if history in unique_stuff:
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ else:
+ unique_stuff[ history ] = []
+ for hda in hdas:
+ if hda not in unique_stuff[ history ]:
+ unique_stuff[ history ].append( hda )
+ %>
+ %endfor
+ %endfor
+ %for history, hdas in unique_stuff.items():
<div class="form-row">
<label>History</label>
${history.name}
@@ -154,19 +216,17 @@
%endif
</div>
%endif
- %if no_change_needed:
- <div class="form-row">
- <input type="radio" name="action" value="share"> Share anyway
- %if can_change:
- (don't change any permissions)
- %endif
- </div>
- %endif
+ <div class="form-row">
+ <input type="radio" name="action" value="share_anyway"> Share anyway
+ %if can_change:
+ (don't change any permissions)
+ %endif
+ </div>
<div class="form-row">
<input type="radio" name="action" value="no_share"> Don't share
</div>
<div class="form-row">
- <input type="submit" name="share_proceed_button" value="Go"><br/>
+ <input type="submit" name="share_restricted_button" value="Go"><br/>
</div>
</form>
%endif
diff -r b26e2ef8726c -r 533ae45c4440 templates/history/sharing.mako
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/history/sharing.mako Mon Jun 29 16:30:16 2009 -0400
@@ -0,0 +1,75 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<h2>Public access via link</h2>
+
+%if msg:
+ ${render_msg( msg, messagetype )}
+%endif
+
+%for history in histories:
+ <p>
+ %if history.importable:
+ Send the following URL to users as an easy way for them to import the history, making a copy of their own:
+ <% url = h.url_for( controller='history', action='imp', id=trans.security.encode_id(history.id), qualified=True ) %>
+ <blockquote>
+ <a href="${url}">${url}</a>
+ </blockquote>
+ <br/>
+ <form action="${h.url_for( controller='history', action='sharing', id=trans.security.encode_id( history.id ) )}" method="POST">
+ <input class="action-button" type="submit" name="disable_import_via_link" value="Disable import via link">
+ </form>
+ %else:
+ This history is currently restricted (only you and the users listed below
+ can access it). Enabling the following option will generate a URL that you
+ can give to a user to allow them to import this history.
+ <br/>
+ <form action="${h.url_for( action='sharing', id=trans.security.encode_id(history.id) )}" method="POST">
+ <input class="action-button" type="submit" name="enable_import_via_link" value="Enable import via link">
+ </form>
+ %endif
+ </p>
+ <h2>Sharing with specific users</h2>
+ %if history.users_shared_with:
+ <ul class="manage-table-actions">
+ <li>
+ <a class="action-button" href="${h.url_for( controller='history', action='share', id=trans.security.encode_id( history.id ) )}">
+ <span>Share with another user</span>
+ </a>
+ </li>
+ </ul>
+ <p>
+ The following users will see this history in their list of histories
+ shared with them by others, and they will be able to create their own copy of it:
+ </p>
+ <table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <th>History '${history.name}' currently shared with</th>
+ <th></th>
+ </tr>
+ %for i, association in enumerate( history.users_shared_with ):
+ <% user = association.user %>
+ <tr>
+ <td>
+ ${user.email}
+ <a id="user-${i}-popup" class="popup-arrow" style="display: none;">▼</a>
+ </td>
+ <td>
+ %if len( histories ) == 1:
+ ## Only allow unsharing if we're dealing with 1 history, otherwise
+ ## page refreshes screw things up
+ <div popupmenu="user-${i}-popup">
+ <a class="action-button" href="${h.url_for( controller='history', action='sharing', id=trans.security.encode_id( history.id ), unshare_user=trans.security.encode_id( user.id ) )}">Unshare</a>
+ </div>
+ %endif
+ </td>
+ </tr>
+ %endfor
+ </table>
+ %else:
+ <p>You have not shared this history with any users.</p>
+ <a class="action-button" href="${h.url_for( controller='history', action='share', id=trans.security.encode_id(history.id) )}">
+ <span>Share with another user</span>
+ </a>
+ %endif
+%endfor
diff -r b26e2ef8726c -r 533ae45c4440 test/base/twilltestcase.py
--- a/test/base/twilltestcase.py Fri Jun 26 09:22:31 2009 -0400
+++ b/test/base/twilltestcase.py Mon Jun 29 16:30:16 2009 -0400
@@ -9,7 +9,8 @@
from twill.other_packages._mechanize_dist import ClientForm
pkg_resources.require( "elementtree" )
from elementtree import ElementTree
-
+from galaxy.web import security
+
buffer = StringIO.StringIO()
#Force twill to log to a buffer -- FIXME: Should this go to stdout and be captured by nose?
@@ -23,13 +24,15 @@
class TwillTestCase( unittest.TestCase ):
def setUp( self ):
+ # Security helper
+ self.security = security.SecurityHelper( id_secret='changethisinproductiontoo' )
self.history_id = os.environ.get( 'GALAXY_TEST_HISTORY_ID', None )
self.host = os.environ.get( 'GALAXY_TEST_HOST' )
self.port = os.environ.get( 'GALAXY_TEST_PORT' )
self.url = "http://%s:%s" % ( self.host, self.port )
self.file_dir = os.environ.get( 'GALAXY_TEST_FILE_DIR' )
self.home()
- self.set_history()
+ #self.set_history()
# Functions associated with files
def files_diff( self, file1, file2 ):
@@ -71,6 +74,7 @@
def upload_file( self, filename, ftype='auto', dbkey='unspecified (?)' ):
"""Uploads a file"""
filename = self.get_filename(filename)
+ self.home()
self.visit_page( "tool_runner/index?tool_id=upload1" )
try:
tc.fv("1","file_type", ftype)
@@ -79,9 +83,16 @@
tc.submit("runtool_btn")
self.home()
except AssertionError, err:
- errmsg = 'The file doesn\'t exsit. Please check' % file
+ errmsg = "The file (%s) doesn't exist." % filename
errmsg += str( err )
raise AssertionError( errmsg )
+ # Make sure every history item has a valid hid
+ hids = self.get_hids_in_history()
+ for hid in hids:
+ try:
+ valid_hid = int( hid )
+ except:
+ raise AssertionError, "Invalid hid (%s) created when uploading file %s" % ( hid, filename )
def upload_url_paste( self, url_paste, ftype='auto', dbkey='unspecified (?)' ):
"""Pasted data in the upload utility"""
self.visit_page( "tool_runner/index?tool_id=upload1" )
@@ -94,6 +105,13 @@
except Exception, e:
errmsg = "Problem executing upload utility using url_paste: %s" % str( e )
raise AssertionError( e )
+ # Make sure every history item has a valid hid
+ hids = self.get_hids_in_history()
+ for hid in hids:
+ try:
+ valid_hid = int( hid )
+ except:
+ raise AssertionError, "Invalid hid (%s) created when pasting %s" % ( hid, url_paste )
# Functions associated with histories
def check_history_for_errors( self ):
@@ -115,27 +133,30 @@
self.visit_page( "clear_history" )
self.check_history_for_string( 'Your history is empty' )
self.home()
- def delete_history( self, id='' ):
+ def delete_history( self, id ):
"""Deletes one or more histories"""
- history_list = self.get_histories()
+ history_list = self.get_histories_as_data_list()
self.assertTrue( history_list )
- num_deleted = 1
- if not id:
- history = history_list[0]
- id = history.get( 'id' )
- else:
- num_deleted = len( id.split( ',' ) )
+ num_deleted = len( id.split( ',' ) )
+ self.home()
self.visit_page( "history/list?operation=delete&id=%s" % ( id ) )
check_str = 'Deleted %d histories' % num_deleted
self.check_page_for_string( check_str )
self.home()
- def get_histories( self ):
- """Returns all histories"""
+ def delete_current_history( self, check_str='' ):
+ """Deletes the current history"""
+ self.home()
+ self.visit_page( "history/delete_current" )
+ if check_str:
+ self.check_page_for_string( check_str )
+ self.home()
+ def get_histories_as_data_list( self ):
+ """Returns the data elements of all histories"""
tree = self.histories_as_xml_tree()
data_list = [ elem for elem in tree.findall("data") ]
return data_list
- def get_history( self, show_deleted=False ):
- """Returns a history"""
+ def get_history_as_data_list( self, show_deleted=False ):
+ """Returns the data elements of a history"""
tree = self.history_as_xml_tree( show_deleted=show_deleted )
data_list = [ elem for elem in tree.findall("data") ]
return data_list
@@ -153,31 +174,24 @@
xml = self.last_page()
tree = ElementTree.fromstring(xml)
return tree
- def history_options( self, check_str='', upload=False ):
+ def history_options( self, user=False, active_datasets=False, activatable_datasets=False, histories_shared_by_others=False ):
"""Mimics user clicking on history options link"""
- self.visit_page( "history_options" )
- if check_str:
- self.check_page_for_string( check_str )
- else:
- self.check_page_for_string( 'Rename</a> current history' )
+ self.home()
+ self.visit_page( "root/history_options" )
+ if user:
self.check_page_for_string( 'List</a> previously stored histories' )
- self.check_page_for_string( 'Construct workflow</a> from the current history' )
+ if active_datasets:
+ self.check_page_for_string( 'Create</a> a new empty history' )
+ self.check_page_for_string( 'Construct workflow</a> from current history' )
+ self.check_page_for_string( 'Clone</a> current history' )
self.check_page_for_string( 'Share</a> current history' )
- # Tests for changing default history permissions are done in test_security_and_libraries.py
- self.check_page_for_string( 'Change default permissions</a> for the current history' )
- self.check_page_for_string( 'Show deleted</a> datasets in history' )
- self.check_page_for_string( 'Delete</a> current history' )
- # Need to add a history item in order to create a new empty history
- try:
- self.check_page_for_string( 'Create</a> a new empty history' )
- raise AssertionError, "Incorrectly able to create a new empty history when the current history is empty."
- except:
- pass
- if upload:
- self.upload_file( '1.bed', dbkey='hg18' )
- self.home()
- self.visit_page( "history_options" )
- self.check_page_for_string( 'Create</a> a new empty history' )
+ self.check_page_for_string( 'Change default permissions</a> for current history' )
+ if histories_shared_by_others:
+ self.check_page_for_string( 'List</a> histories shared with you by others' )
+ if activatable_datasets:
+ self.check_page_for_string( 'Show deleted</a> datasets in current history' )
+ self.check_page_for_string( 'Rename</a> current history' )
+ self.check_page_for_string( 'Delete</a> current history' )
self.home()
def new_history( self, name=None ):
"""Creates a new, empty history"""
@@ -198,26 +212,63 @@
def set_history( self ):
"""Sets the history (stores the cookies for this run)"""
if self.history_id:
+ self.home()
self.visit_page( "history?id=%s" % self.history_id )
else:
self.new_history()
self.home()
- def share_history( self, id, email, check_str, check_str2='', action=None, action_check_str=None ):
- """Share a history different users"""
- self.visit_url( "%s/history/share?id=%s&email=%s&history_share_btn=Submit" % ( self.url, id, email ) )
- self.check_page_for_string( check_str )
+ def share_current_history( self, email, check_str='', check_str_after_submit='', check_str_after_submit2='',
+ action='', action_check_str='', action_check_str_after_submit='' ):
+ """Share the current history with different users"""
+ self.visit_url( "%s/history/share" % self.url )
+ if check_str:
+ self.check_page_for_string( check_str )
+ tc.fv( 'share', 'email', email )
+ tc.submit( 'share_button' )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
+ if check_str_after_submit2:
+ self.check_page_for_string( check_str_after_submit2 )
+ if action:
+ # If we have an action, then we are sharing datasets with users that do not have access permissions on them
+ if action_check_str:
+ self.check_page_for_string( action_check_str )
+ tc.fv( 'share_restricted', 'action', action )
+ tc.submit( "share_restricted_button" )
+ if action_check_str_after_submit:
+ self.check_page_for_string( action_check_str_after_submit )
+ self.home()
+ def share_histories_with_users( self, ids, emails, check_str1='', check_str2='',
+ check_str_after_submit='', action=None, action_check_str=None ):
+ """Share one or more histories with one or more different users"""
+ self.visit_url( "%s/history/list?id=%s&operation=Share" % ( self.url, ids ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
if check_str2:
self.check_page_for_string( check_str2 )
+ tc.fv( 'share', 'email', emails )
+ tc.submit( 'share_button' )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
if action:
# If we have an action, then we are sharing datasets with users that do not have access permissions on them
- tc.fv( '1', 'action', action )
- tc.submit( "share_proceed_button" )
+ tc.fv( 'share_restricted', 'action', action )
+ tc.submit( "share_restricted_button" )
if action_check_str:
self.check_page_for_string( action_check_str )
self.home()
+ def unshare_history( self, history_id, user_id, check_str1='', check_str2='', check_str_after_submit='' ):
+ """Unshare a history that has been shared with another user"""
+ self.visit_url( "%s/history/list?id=%s&operation=sharing" % ( self.url, history_id ) )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ self.visit_url( "%s/history/sharing?unshare_user=%s&id=%s" % ( self.url, user_id, history_id ) )
+ self.home()
def switch_history( self, id='', name='' ):
"""Switches to a history in the current list of histories"""
- data_list = self.get_histories()
+ data_list = self.get_histories_as_data_list()
self.assertTrue( data_list )
if not id:
history = history_list[0]
@@ -227,6 +278,7 @@
self.check_history_for_string( name )
self.home()
def view_stored_active_histories( self, check_str='' ):
+ self.home()
self.visit_page( "history/list" )
self.check_page_for_string( 'Stored histories' )
self.check_page_for_string( '<input type="checkbox" name="id" value=' )
@@ -237,12 +289,57 @@
self.check_page_for_string( check_str )
self.home()
def view_stored_deleted_histories( self, check_str='' ):
+ self.home()
self.visit_page( "history/list?f-deleted=True" )
self.check_page_for_string( 'Stored histories' )
self.check_page_for_string( '<input type="checkbox" name="id" value=' )
self.check_page_for_string( 'operation=Undelete&id' )
if check_str:
self.check_page_for_string( check_str )
+ self.home()
+ def view_shared_histories( self, check_str='', check_str2='' ):
+ self.home()
+ self.visit_page( "history/list_shared" )
+ if check_str:
+ self.check_page_for_string( check_str )
+ if check_str2:
+ self.check_page_for_string( check_str2 )
+ self.home()
+ def clone_history( self, history_id, check_str1='' ):
+ self.home()
+ self.visit_page( "history/clone?id=%s" % history_id )
+ if check_str1:
+ self.check_page_for_string( check_str1 )
+ self.home()
+ def enable_import_via_link( self, history_id, check_str='', check_str_after_submit='' ):
+ self.home()
+ self.visit_page( "history/list?operation=sharing&id=%s" % history_id )
+ if check_str:
+ self.check_page_for_string( check_str )
+ # twill barfs on this form, possibly because it contains no fields, but not sure.
+ # In any case, we have to mimic the form submission
+ self.home()
+ self.visit_page( 'history/sharing?id=%s&enable_import_via_link=True' % history_id )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
+ self.home()
+ def disable_import_via_link( self, history_id, check_str='', check_str_after_submit='' ):
+ self.home()
+ self.visit_page( "history/list?operation=sharing&id=%s" % history_id )
+ if check_str:
+ self.check_page_for_string( check_str )
+ # twill barfs on this form, possibly because it contains no fields, but not sure.
+ # In any case, we have to mimic the form submission
+ self.home()
+ self.visit_page( 'history/sharing?id=%s&disable_import_via_link=True' % history_id )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
+ self.home()
+ def import_history_via_url( self, history_id, email, check_str_after_submit='' ):
+ self.home()
+ self.visit_page( "history/imp?&id=%s" % history_id )
+ if check_str_after_submit:
+ self.check_page_for_string( check_str_after_submit )
self.home()
# Functions associated with datasets (history items) and meta data
@@ -260,7 +357,7 @@
def check_metadata_for_string( self, patt, hid=None ):
"""Looks for 'patt' in the edit page when editing a dataset"""
- data_list = self.get_history()
+ data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
if hid is None: # take last hid
elem = data_list[-1]
@@ -276,7 +373,7 @@
except:
raise AssertionError, "Invalid hid '%s' - must be int" % hid
hid = str(hid)
- data_list = self.get_history()
+ data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
elems = [ elem for elem in data_list if elem.get( 'hid' ) == hid ]
self.assertEqual( len( elems ), 1 )
@@ -291,7 +388,7 @@
except:
raise AssertionError, "Invalid hid '%s' - must be int" % hid
hid = str( hid )
- data_list = self.get_history( show_deleted=show_deleted )
+ data_list = self.get_history_as_data_list( show_deleted=show_deleted )
self.assertTrue( data_list )
elems = [ elem for elem in data_list if elem.get( 'hid' ) == hid ]
self.assertEqual( len( elems ), 1 )
@@ -348,7 +445,8 @@
tc.submit( 'change' )
self.check_page_for_string( 'Edit Attributes' )
self.home()
- def copy_history_item( self, source_dataset_ids='', target_history_ids=[], all_target_history_ids=[], deleted_history_ids=[] ):
+ def copy_history_item( self, source_dataset_ids='', target_history_ids=[], all_target_history_ids=[],
+ deleted_history_ids=[] ):
"""Copy 1 or more history_dataset_associations to 1 or more histories"""
self.home()
self.visit_url( "%s/dataset/copy_datasets?source_dataset_ids=%s" % ( self.url, source_dataset_ids ) )
@@ -371,31 +469,28 @@
check_str = '%d datasets copied to %d histories.' % ( no_source_ids, len( target_history_ids ) )
self.check_page_for_string( check_str )
self.home()
- def get_dataset_ids_in_history( self ):
- """Returns the ids of datasets in a history"""
- data_list = self.get_history()
+ def get_hids_in_history( self ):
+ """Returns the list of hid values for items in a history"""
+ data_list = self.get_history_as_data_list()
hids = []
for elem in data_list:
hid = elem.get('hid')
hids.append(hid)
return hids
-
- def get_dataset_ids_in_histories( self ):
- """Returns the ids of datasets in all histories"""
- data_list = self.get_histories()
+ def get_hids_in_histories( self ):
+ """Returns the list of hids values for items in all histories"""
+ data_list = self.get_histories_as_data_list()
hids = []
for elem in data_list:
hid = elem.get('hid')
hids.append(hid)
return hids
-
def verify_dataset_correctness( self, filename, hid=None, wait=True ):
"""Verifies that the attributes and contents of a history item meet expectations"""
- if wait: self.wait() #wait for job to finish
-
- data_list = self.get_history()
+ if wait:
+ self.wait() #wait for job to finish
+ data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
-
if hid is None: # take last hid
elem = data_list[-1]
hid = str( elem.get('hid') )
@@ -404,10 +499,8 @@
elems = [ elem for elem in data_list if elem.get('hid') == hid ]
self.assertTrue( len(elems) == 1 )
elem = elems[0]
-
self.assertTrue( hid )
self._assert_dataset_state( elem, 'ok' )
-
if self.is_zipped( filename ):
errmsg = 'History item %s is a zip archive which includes invalid files:\n' % hid
zip_file = zipfile.ZipFile( filename, "r" )
@@ -422,6 +515,7 @@
else:
local_name = self.get_filename( filename )
temp_name = self.get_filename( 'temp_%s' % filename )
+ self.home()
self.visit_page( "display?hid=" + hid )
data = self.last_page()
file( temp_name, 'wb' ).write(data)
@@ -455,7 +549,7 @@
def verify_genome_build( self, dbkey='hg17' ):
"""Verifies that the last used genome_build at history id 'hid' is as expected"""
- data_list = self.get_history()
+ data_list = self.get_history_as_data_list()
self.assertTrue( data_list )
elems = [ elem for elem in data_list ]
elem = elems[-1]
diff -r b26e2ef8726c -r 533ae45c4440 test/functional/__init__.py
--- a/test/functional/__init__.py Fri Jun 26 09:22:31 2009 -0400
+++ b/test/functional/__init__.py Mon Jun 29 16:30:16 2009 -0400
@@ -24,7 +24,7 @@
# server (for running the tests against a running instance)
default_galaxy_test_host = "localhost"
-default_galaxy_test_port = "9999"
+default_galaxy_test_port = "8777"
default_galaxy_locales = 'en'
galaxy_test_file_dir = "test-data"
server = None
@@ -63,10 +63,10 @@
default_cluster_job_runner = os.environ['GALAXY_TEST_DEF_RUNNER']
else:
default_cluster_job_runner = 'local:///'
-
app = UniverseApplication( job_queue_workers = 5,
start_job_runners = start_job_runners,
default_cluster_job_runner = default_cluster_job_runner,
+ id_secret = 'changethisinproductiontoo',
template_path = "templates",
database_connection = database_connection,
file_path = file_path,
diff -r b26e2ef8726c -r 533ae45c4440 test/functional/test_DNAse_flanked_genes.py
--- a/test/functional/test_DNAse_flanked_genes.py Fri Jun 26 09:22:31 2009 -0400
+++ b/test/functional/test_DNAse_flanked_genes.py Mon Jun 29 16:30:16 2009 -0400
@@ -6,10 +6,12 @@
class AnalysisDNAseHSSFlankedGenes( TwillTestCase ):
def test_get_DNAseHSS_flanked_genes( self ):
- self.login()
- self.new_history()
- global history1
- history1 = galaxy.model.History.query() \
+ self.logout()
+ self.login( email='test(a)bx.psu.edu' )
+ admin_user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test(a)bx.psu.edu' ).one()
+ self.new_history( name='DNAseHSS_flanked_genes' )
+ history1 = 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()
track_params = dict(
db="hg17",
@@ -85,5 +87,5 @@
self.run_tool( 'Filter1', input="4", cond="c17==1000" )
self.wait()
self.verify_dataset_correctness( 'filteredJoinedFlanksDNAse.dat' )
- self.delete_history()
+ self.delete_history( self.security.encode_id( history1.id ) )
self.logout()
diff -r b26e2ef8726c -r 533ae45c4440 test/functional/test_get_data.py
--- a/test/functional/test_get_data.py Fri Jun 26 09:22:31 2009 -0400
+++ b/test/functional/test_get_data.py Mon Jun 29 16:30:16 2009 -0400
@@ -6,8 +6,12 @@
def test_000_upload_files_from_disk( self ):
"""Test uploading data files from disk"""
self.logout()
- self.login( email='tst(a)bx.psu.edu' )
- history1 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ self.login( email='test(a)bx.psu.edu' )
+ global admin_user
+ admin_user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test(a)bx.psu.edu' ).one()
+ history1 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
+ galaxy.model.History.table.c.user_id==admin_user.id ) ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
self.upload_file( '1.bed' )
hda1 = galaxy.model.HistoryDatasetAssociation.query() \
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ).first()
@@ -38,24 +42,28 @@
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ).first()
assert hda6 is not None, "Problem retrieving hda6 from database"
self.verify_dataset_correctness( '1.scf.zip', hid=str( hda6.hid ) )
- self.delete_history( id=str( history1.id ) )
+ self.delete_history( id=self.security.encode_id( history1.id ) )
def test_005_url_paste( self ):
"""Test url paste behavior"""
# Deleting the current history should have created a new history
self.check_history_for_string( 'Your history is empty' )
- history2 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history2 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
+ galaxy.model.History.table.c.user_id==admin_user.id ) ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
self.upload_url_paste( 'hello world' )
self.check_history_for_string( 'Pasted Entry' )
self.check_history_for_string( 'hello world' )
self.upload_url_paste( u'hello world' )
self.check_history_for_string( 'Pasted Entry' )
self.check_history_for_string( 'hello world' )
- self.delete_history( id=str( history2.id ) )
+ self.delete_history( id=self.security.encode_id( history2.id ) )
def test_010_upload_encode_data( self ):
"""Test uploading encode data"""
# Deleting the current history should have created a new history
self.check_history_for_string( 'Your history is empty' )
- history3 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history3 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
+ galaxy.model.History.table.c.user_id==admin_user.id ) ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
self.run_tool( 'encode_import_chromatin_and_chromosomes1', hg17=['cc.EarlyRepSeg.20051216.bed'] )
self.wait()
hda7 = galaxy.model.HistoryDatasetAssociation.query() \
@@ -68,7 +76,4 @@
.order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ).first()
assert hda8 is not None, "Problem retrieving hda8 from database"
self.verify_dataset_correctness( 'sc_3D_cds.bed', hid=str( hda8.hid ) )
- self.delete_history( id=str( history3.id ) )
- def test_015_reset_data_for_later_test_runs( self ):
- """Reseting data to enable later test runs to pass"""
- self.logout()
+ self.delete_history( id=self.security.encode_id( history3.id ) )
diff -r b26e2ef8726c -r 533ae45c4440 test/functional/test_history_functions.py
--- a/test/functional/test_history_functions.py Fri Jun 26 09:22:31 2009 -0400
+++ b/test/functional/test_history_functions.py Mon Jun 29 16:30:16 2009 -0400
@@ -5,12 +5,11 @@
class TestHistory( TwillTestCase ):
- def test_000_history_options_when_not_logged_in( self ):
- """Testing history options when not logged in"""
+ def test_000_history_behavior_between_logout_login( self ):
+ """Testing history behavior between logout and login"""
self.logout()
- check_str = 'logged in</a> to store or switch histories.'
- self.history_options( check_str=check_str )
- # Make sure we have created the following accounts
+ self.history_options()
+ # Make sure we have created the following 4 accounts
self.login( email='test1(a)bx.psu.edu' )
global regular_user1
regular_user1 = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test1(a)bx.psu.edu' ).first()
@@ -25,14 +24,12 @@
global regular_user3
regular_user3 = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test3(a)bx.psu.edu' ).first()
assert regular_user3 is not None, 'Problem retrieving user with email "test3(a)bx.psu.edu" from the database'
- def test_005_deleting_histories( self ):
- """Testing deleting histories"""
self.logout()
self.login( email='test(a)bx.psu.edu' )
global admin_user
- admin_user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test(a)bx.psu.edu' ).first()
+ admin_user = galaxy.model.User.filter( galaxy.model.User.table.c.email=='test(a)bx.psu.edu' ).one()
assert admin_user is not None, 'Problem retrieving user with email "test(a)bx.psu.edu" from the database'
- # Get the admin_user private role
+ # Get the admin_user private role for later use
global admin_user_private_role
admin_user_private_role = None
for role in admin_user.all_roles():
@@ -41,27 +38,48 @@
break
if not admin_user_private_role:
raise AssertionError( "Private role not found for user '%s'" % admin_user.email )
- latest_history = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
- assert latest_history is not None, "Problem retrieving latest history from database"
- assert not latest_history.deleted, "After login, associated history is deleted"
- self.delete_history( str( latest_history.id ) )
- latest_history.refresh()
- if not latest_history.deleted:
- raise AssertionError, "Problem deleting history id %d" % latest_history.id
+ historyA = 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()
+ assert historyA is not None, "Problem retrieving historyA from database"
+ assert not historyA.deleted, "After login, historyA is deleted"
+ # Make sure the last used history is set for the next session after login
+ self.logout()
+ self.login( email=admin_user.email )
+ historyB = 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()
+ assert historyB is not None, "Problem retrieving historyB from database"
+ assert historyA.id == historyB.id, "After the same user logged out and back in, their last used history was not associated with their new session"
+ def test_005_deleting_histories( self ):
+ """Testing deleting histories"""
+ # Logged in as admin_user
+ historyB = 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()
+ assert historyB is not None, "Problem retrieving historyB from database"
+ self.delete_history( self.security.encode_id( historyB.id ) )
+ historyB.refresh()
+ if not historyB.deleted:
+ raise AssertionError, "Problem deleting history id %d" % historyB.id
# Since we deleted the current history, make sure the history frame was refreshed
self.check_history_for_string( 'Your history is empty.' )
# We'll now test deleting a list of histories
# After deleting the current history, a new one should have been created
global history1
- history1 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history1 = 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()
assert history1 is not None, "Problem retrieving history1 from database"
self.upload_file( '1.bed', dbkey='hg18' )
self.new_history( name=urllib.quote( 'history2' ) )
global history2
- history2 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history2 = 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()
assert history2 is not None, "Problem retrieving history2 from database"
self.upload_file( '2.bed', dbkey='hg18' )
- ids = '%s,%s' % ( str( history1.id ), str( history2.id ) )
+ ids = '%s,%s' % ( self.security.encode_id( history1.id ), self.security.encode_id( history2.id ) )
self.delete_history( ids )
# Since we deleted the current history, make sure the history frame was refreshed
self.check_history_for_string( 'Your history is empty.' )
@@ -87,116 +105,153 @@
raise AssertionError, "Problem deleting history id %d" % history2.id
if not history2.default_permissions:
raise AssertionError, "Default permissions were incorrectly deleted from the db for history id %d when it was deleted" % history2.id
- def test_010_history_options_when_logged_in( self ):
- """Testing history options when logged in"""
- self.history_options()
- def test_015_history_rename( self ):
+ # Current history is empty
+ self.history_options( user=True )
+ def test_010_history_rename( self ):
"""Testing renaming a history"""
+ # Logged in as admin_user
global history3
- history3 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history3 = galaxy.model.History \
+ .filter( galaxy.model.History.table.c.deleted==False ) \
+ .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
+ .first()
assert history3 is not None, "Problem retrieving history3 from database"
if history3.deleted:
raise AssertionError, "History id %d deleted when it should not be" % latest_history.id
- self.rename_history( str( history3.id ), history3.name, new_name=urllib.quote( 'history 3' ) )
- def test_020_history_list( self ):
- """Testing viewing previously stored histories"""
+ self.rename_history( self.security.encode_id( history3.id ), history3.name, new_name=urllib.quote( 'history 3' ) )
+ history3.refresh()
+ def test_015_history_list( self ):
+ """Testing viewing previously stored active histories"""
+ # Logged in as admin_user
self.view_stored_active_histories()
- def test_025_history_share( self ):
- """Testing sharing histories containing only public datasets"""
+ def test_020_share_current_history( self ):
+ """Testing sharing the current history which contains only public datasets"""
+ # Logged in as admin_user
+ # Test sharing an empty history - current history is history3
+ self.share_current_history( regular_user1.email,
+ check_str=history3.name,
+ check_str_after_submit='You cannot share an empty history.' )
+ # Make history3 sharable by adding a dataset
+ self.upload_file( '1.bed', dbkey='hg18' )
+ # Current history is no longer empty
+ self.history_options( user=True, active_datasets=True, activatable_datasets=True )
+ # Test sharing history3 with yourself
+ self.share_current_history( admin_user.email,
+ check_str=history3.name,
+ check_str_after_submit='You cannot send histories to yourself.' )
+ # Share history3 with 1 valid user
+ self.share_current_history( regular_user1.email,
+ check_str=history3.name,
+ check_str_after_submit='History (%s) now shared with: 1 users' % history3.name )
+ # Check out list of histories to make sure history3 was shared
+ self.view_stored_active_histories( check_str='operation=sharing&id=%s">shared' % self.security.encode_id( history3.id ) )
+ # Enable importing history3 via a URL
+ self.enable_import_via_link( self.security.encode_id( history3.id ),
+ check_str='Unshare',
+ check_str_after_submit='Send the following URL to users' )
+ # Make sure history3 is now import-able
history3.refresh()
- self.upload_file( '1.bed', dbkey='hg18' )
- # Test sharing a history with yourself
- check_str = "You can't send histories to yourself."
- self.share_history( str( history3.id ), 'test(a)bx.psu.edu', check_str )
- # Share a history with 1 valid user
- check_str = 'Histories (%s) have been shared with: %s' % ( history3.name, regular_user1.email )
- self.share_history( str( history3.id ), regular_user1.email, check_str )
- # We need to keep track of all shared histories so they can later be deleted
- global history3_copy1
- history3_copy1 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
- assert history3_copy1 is not None, "Problem retrieving history3_copy1 from database"
+ if not history3.importable:
+ raise AssertionError, "History 3 is not marked as importable after enable_import_via_link"
+ # Try importing history3
+ self.import_history_via_url( self.security.encode_id( history3.id ),
+ admin_user.email,
+ check_str_after_submit='You cannot import your own history.' )
+ # Disable the import link for history3
+ self.disable_import_via_link( self.security.encode_id( history3.id ),
+ check_str='Send the following URL to users',
+ check_str_after_submit='Enable import via link' )
+ # Try importing history3 after disabling the URL
+ self.import_history_via_url( self.security.encode_id( history3.id ),
+ admin_user.email,
+ check_str_after_submit='The owner of this history has disabled imports via this link.' )
+ # Test sharing history3 with an invalid user
+ self.share_current_history( 'jack(a)jill.com',
+ check_str_after_submit='jack(a)jill.com is not a valid Galaxy user.' )
+
+
+
+
+
+ def test_025_delete_shared_current_history( self ):
+ """Testing deleting the current history after it was shared"""
+ # Logged in as admin_user
+ self.delete_current_history( check_str="History (%s) has been shared with others, unshare it before deleting it." % history3.name )
+ def test_030_clone_shared_history( self ):
+ """Testing cloning a shared history"""
+ # logged in as admin user
self.logout()
self.login( email=regular_user1.email )
- check_str = '%s from %s' % ( history3.name, admin_user.email )
+ # Shared history3 affects history options
+ self.history_options( user=True, histories_shared_by_others=True )
+ # Shared history3 should be in regular_user1's list of shared histories
+ self.view_shared_histories( check_str=history3.name, check_str2=admin_user.email )
+ self.clone_history( self.security.encode_id( history3.id ),
+ check_str1='is now included in your list of stored histories.' )
+ global history3_clone1
+ history3_clone1 = 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()
+ assert history3_clone1 is not None, "Problem retrieving history3_clone1 from database"
+ # Check list of histories to make sure shared history3 was cloned
+ check_str = "Clone of '%s' shared by '%s'" % ( history3.name, admin_user.email )
self.view_stored_active_histories( check_str=check_str )
- # Need to delete history3_copy1
- self.delete_history( id=str( history3_copy1.id ) )
+ def test_035_clone_current_history( self ):
+ """Testing cloning the current history"""
+ # logged in as regular_user1
self.logout()
self.login( email=admin_user.email )
- # Test sharing a history with an invalid user
- email = 'jack(a)jill.com'
- check_str = '%s is not a valid Galaxy user.' % email
- self.share_history( str( history3.id ), email, check_str )
- # Test sharing multiple histories with multiple users
+ self.clone_history( self.security.encode_id( history3.id ),
+ check_str1='is now included in your list of stored histories.' )
+ global history3_clone2
+ history3_clone2 = 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()
+ assert history3_clone2 is not None, "Problem retrieving history3_clone2 from database"
+ # Check list of histories to make sure shared history3 was cloned
+ self.view_stored_active_histories( check_str="Clone of '%s'" % history3.name )
+ def test_040_sharing_mulitple_histories_with_multiple_users( self ):
+ """Testing sharing multiple histories containing only public datasets with multiple users"""
+ # Logged in as admin_user
self.new_history()
global history4
- history4 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history4 = 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()
assert history4 is not None, "Problem retrieving history4 from database"
- self.rename_history( str( history4.id ), history4.name, new_name=urllib.quote( 'history 4' ) )
+ self.rename_history( self.security.encode_id( history4.id ), history4.name, new_name=urllib.quote( 'history 4' ) )
history4.refresh()
self.upload_file( '2.bed', dbkey='hg18' )
- id = '%s,%s' % ( str( history3.id ), str( history4.id ) )
- name = '%s,%s' % ( history3.name, history4.name )
- email = '%s,%s' % ( regular_user2.email, regular_user3.email )
- check_str = 'Histories (%s) have been shared with: %s' % ( name, email )
- self.share_history( id, email, check_str )
- # We need to keep track of all shared histories so they can later be deleted
- history3_copy_name = "%s from %s" % ( history3.name, admin_user.email )
- history3_to_use_for_regular_user2 = galaxy.model.History \
- .filter( and_( galaxy.model.History.table.c.name==history3_copy_name,
- galaxy.model.History.table.c.user_id==regular_user2.id,
- galaxy.model.History.table.c.deleted==False ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- assert history3_to_use_for_regular_user2 is not None, "Problem retrieving history3_to_use_for_regular_user2 from database"
- history3_to_use_for_regular_user3 = galaxy.model.History \
- .filter( and_( galaxy.model.History.table.c.name==history3_copy_name,
- galaxy.model.History.table.c.user_id==regular_user3.id,
- galaxy.model.History.table.c.deleted==False ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- assert history3_to_use_for_regular_user3 is not None, "Problem retrieving history3_to_use_for_regular_user3 from database"
- history4_copy_name = "%s from %s" % ( history4.name, admin_user.email )
- history4_to_use_for_regular_user2 = galaxy.model.History \
- .filter( and_( galaxy.model.History.table.c.name==history4_copy_name,
- galaxy.model.History.table.c.user_id==regular_user2.id,
- galaxy.model.History.table.c.deleted==False ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- assert history4_to_use_for_regular_user2 is not None, "Problem retrieving history4_to_use_for_regular_user2 from database"
- history4_to_use_for_regular_user3 = galaxy.model.History \
- .filter( and_( galaxy.model.History.table.c.name==history4_copy_name,
- galaxy.model.History.table.c.user_id==regular_user3.id,
- galaxy.model.History.table.c.deleted==False ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ) \
- .first()
- assert history4_to_use_for_regular_user3 is not None, "Problem retrieving history4_to_use_for_regular_user3 from database"
+ ids = '%s,%s' % ( self.security.encode_id( history3.id ), self.security.encode_id( history4.id ) )
+ emails = '%s,%s' % ( regular_user2.email, regular_user3.email )
+ check_str_after_submit = 'History (%s) now shared with: 3 users.' % history3.name
+ self.share_histories_with_users( ids,
+ emails,
+ check_str1='Share 2 histories',
+ check_str2=history4.name,
+ check_str_after_submit=check_str_after_submit )
self.logout()
self.login( email=regular_user2.email )
- check_str = '%s from %s' % ( history3.name, admin_user.email )
- self.view_stored_active_histories( check_str=check_str )
- check_str = '%s from %s' % ( history4.name, admin_user.email )
- self.view_stored_active_histories( check_str=check_str )
- # Need to delete the copied histories, so later test runs are valid
- self.delete_history( id=str( history3_to_use_for_regular_user2.id ) )
- self.delete_history( id=str( history4_to_use_for_regular_user2.id ) )
+ # Shared history3 should be in regular_user2's list of shared histories
+ self.view_shared_histories( check_str=history3.name, check_str2=admin_user.email )
self.logout()
self.login( email=regular_user3.email )
- check_str = '%s from %s' % ( history3.name, admin_user.email )
- self.view_stored_active_histories( check_str=check_str )
- check_str = '%s from %s' % ( history4.name, admin_user.email )
- self.view_stored_active_histories( check_str=check_str )
- # Need to delete the copied histories, so later test runs are valid
- self.delete_history( id=str( history3_to_use_for_regular_user3.id ) )
- self.delete_history( id=str( history4_to_use_for_regular_user3.id ) )
+ # Shared history3 should be in regular_user3's list of shared histories
+ self.view_shared_histories( check_str=history3.name, check_str2=admin_user.email )
+ def test_045_change_permissions_on_current_history( self ):
+ """Testing changing permissions on the current history"""
+ # Logged in as regular_user3
self.logout()
self.login( email=admin_user.email )
- def test_030_change_permissions_on_current_history( self ):
- """Testing changing permissions on the current history"""
+ # Current history is history4
+ self.new_history()
global history5
- history5 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
+ history5 = 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()
assert history5 is not None, "Problem retrieving history5 from database"
- self.rename_history( str( history5.id ), history5.name, new_name=urllib.quote( 'history5' ) )
+ self.rename_history( self.security.encode_id( history5.id ), history5.name, new_name=urllib.quote( 'history 5' ) )
+ # Current history is hostory5
history5.refresh()
# Due to the limitations of twill ( not functional with the permissions forms ), we're forced
# to do this manually. At this point, we just want to restrict the access permission on history5
@@ -205,81 +260,126 @@
access_action = galaxy.model.Dataset.permitted_actions.DATASET_ACCESS.action
dhp = galaxy.model.DefaultHistoryPermissions( history5, access_action, admin_user_private_role )
dhp.flush()
+ history5.refresh()
+ global history5_default_permissions
+ history5_default_permissions = [ dhp.action for dhp in history5.default_permissions ]
+ # Sort for later comparison
+ history5_default_permissions.sort()
self.upload_file( '1.bed', dbkey='hg18' )
history5_dataset1 = None
for hda in history5.datasets:
if hda.name == '1.bed':
history5_dataset1 = hda.dataset
+ break
assert history5_dataset1 is not None, "Problem retrieving history5_dataset1 from the database"
# The permissions on the dataset should be restricted from sharing with anyone due to the
# inherited history permissions
- restricted = False
- for action in history5_dataset1.actions:
- if action.action == access_action:
- restricted = True
- break
- if not restricted:
- raise AssertionError, "The 'access' permission is not set for history5_dataset1.actions"
- def test_035_sharing_history_by_making_datasets_public( self ):
+ dataset_permissions = [ a.action for a in history5_dataset1.actions ]
+ dataset_permissions.sort()
+ if dataset_permissions != history5_default_permissions:
+ err_msg = "Dataset permissions for history5_dataset1 (%s) were not correctly inherited from history permissions (%s)" \
+ % ( str( dataset_permissions ), str( history5_default_permissions ) )
+ raise AssertionError, err_msg
+ # Make sure when we logout and login, the history default permissions are preserved
+ self.logout()
+ self.login( email=admin_user.email )
+ history5.refresh()
+ current_history_permissions = [ dhp.action for dhp in history5.default_permissions ]
+ current_history_permissions.sort()
+ if current_history_permissions != history5_default_permissions:
+ raise AssertionError, "With logout and login, the history default permissions are not preserved"
+ def test_050_sharing_restricted_history_by_making_datasets_public( self ):
"""Testing sharing a restricted history by making the datasets public"""
- # We're still logged in as admin_user.email
- check_str = 'The following datasets can be shared with %s by updating their permissions' % regular_user1.email
- action_check_str = 'Histories (%s) have been shared with: %s' % ( history5.name, regular_user1.email )
- self.share_history( str( history5.id ), regular_user1.email, check_str, action='public', action_check_str=action_check_str )
- history5_copy1 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
- assert history5_copy1 is not None, "Problem retrieving history5_copy1 from database"
+ # Logged in as admin_user
+ action_check_str = 'The following datasets can be shared with %s by updating their permissions' % regular_user1.email
+ action_check_str_after_submit = 'History (%s) now shared with: 1 users.' % history5.name
+ # Current history is history5
+ self.share_current_history( regular_user1.email,
+ action='public',
+ action_check_str=action_check_str,
+ action_check_str_after_submit=action_check_str_after_submit )
self.logout()
self.login( email=regular_user1.email )
- self.visit_url( "%s/history/list" % self.url )
- self.check_page_for_string( history5_copy1.name )
- # Need to delete history5_copy1 on the history list page for regular_user1
- self.delete_history( id=str( history5_copy1.id ) )
+ # Shared history5 should be in regular_user1's list of shared histories
+ self.view_shared_histories( check_str=history5.name, check_str2=admin_user.email )
+ # Clone restricted history5
+ self.clone_history( self.security.encode_id( history5.id ),
+ check_str1='is now included in your list of stored histories.' )
+ global history5_clone1
+ history5_clone1 = 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()
+ assert history5_clone1 is not None, "Problem retrieving history5_clone1 from database"
+ # Check list of histories to make sure shared history5 was cloned
+ self.view_stored_active_histories( check_str="Clone of '%s'" % history5.name )
+ # Make sure the dataset is accessible
+ self.switch_history( id=self.security.encode_id( history5_clone1.id ), name=history5_clone1.name )
+ self.check_history_for_string( 'chr1' )
self.logout()
self.login( email=admin_user.email )
- def test_040_sharing_history_by_making_new_sharing_role( self ):
+ def test_055_sharing_restricted_history_by_making_new_sharing_role( self ):
"""Testing sharing a restricted history by associating a new sharing role with protected datasets"""
- self.switch_history( id=str( history5.id ), name=history5.name )
# At this point, history5 should have 1 item, 1.bed, which is public. We'll add another
# item which will be private to admin_user due to the permissions on history5
self.upload_file( '2.bed', dbkey='hg18' )
- check_str = 'The following datasets can be shared with %s with no changes' % regular_user1.email
- check_str2 = 'The following datasets can be shared with %s by updating their permissions' % regular_user1.email
- action_check_str = 'Histories (%s) have been shared with: %s' % ( history5.name, regular_user1.email )
- self.share_history( str( history5.id ),
- regular_user1.email,
- check_str,
- check_str2=check_str2,
- action='private',
- action_check_str=action_check_str )
- history5_copy2 = galaxy.model.History.query().order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
- assert history5_copy2 is not None, "Problem retrieving history5_copy2 from database"
+ check_str_after_submit = 'The following datasets can be shared with %s with no changes' % regular_user2.email
+ check_str_after_submit2 = 'The following datasets can be shared with %s by updating their permissions' % regular_user2.email
+ action_check_str_after_submit = 'History (%s) now shared with: 2 users.' % history5.name
+ self.share_current_history( regular_user2.email,
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/d9e58acd4dca
changeset: 2461:d9e58acd4dca
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Mon Jun 29 16:54:41 2009 -0400
description:
Bug fix for my last commit.
1 file(s) affected in this change:
lib/galaxy/model/migrate/versions/0007_sharing_histories.py
diffs (24 lines):
diff -r 533ae45c4440 -r d9e58acd4dca lib/galaxy/model/migrate/versions/0007_sharing_histories.py
--- a/lib/galaxy/model/migrate/versions/0007_sharing_histories.py Mon Jun 29 16:30:16 2009 -0400
+++ b/lib/galaxy/model/migrate/versions/0007_sharing_histories.py Mon Jun 29 16:54:41 2009 -0400
@@ -1,11 +1,15 @@
from sqlalchemy import *
+from sqlalchemy.orm import *
from migrate import *
+import sys, logging
-import datetime
-now = datetime.datetime.utcnow
-
-# Need our custom types, but don't import anything else from model
-from galaxy.model.custom_types import *
+log = logging.getLogger( __name__ )
+log.setLevel(logging.DEBUG)
+handler = logging.StreamHandler( sys.stdout )
+format = "%(name)s %(levelname)s %(asctime)s %(message)s"
+formatter = logging.Formatter( format )
+handler.setFormatter( formatter )
+log.addHandler( handler )
metadata = MetaData( migrate_engine )
1
0

30 Jun '09
details: http://www.bx.psu.edu/hg/galaxy/rev/8ad73e08978e
changeset: 2462:8ad73e08978e
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Mon Jun 29 17:04:18 2009 -0400
description:
Yet another bug fix - not sure why these were not caught in development.
1 file(s) affected in this change:
lib/galaxy/model/migrate/versions/0007_sharing_histories.py
diffs (11 lines):
diff -r d9e58acd4dca -r 8ad73e08978e lib/galaxy/model/migrate/versions/0007_sharing_histories.py
--- a/lib/galaxy/model/migrate/versions/0007_sharing_histories.py Mon Jun 29 16:54:41 2009 -0400
+++ b/lib/galaxy/model/migrate/versions/0007_sharing_histories.py Mon Jun 29 17:04:18 2009 -0400
@@ -1,6 +1,7 @@
from sqlalchemy import *
from sqlalchemy.orm import *
from migrate import *
+from migrate.changeset import *
import sys, logging
log = logging.getLogger( __name__ )
1
0
Hello,
I have two small questions regarding galaxy server configuration:
1. The Galaxy Cookie.
Sometimes I see a fixed 'galaxysession' cookie,
and other times I see a cookie with the name set in
'universe_wsgi.ini' as the "session_key".
I'm not sure when is each one used.
What I'd like to do is run two galaxy servers on the server - I
don't want to cookies to interfere with one another.
(could it have something with using or not using external
authentication?)
2. setting path of Galaxy's file:
There's the big 'database' directory.
Inside it, there are:
files, import, pbs, job_working_directory, beaker_sessions, tmp,
compiled_templates.
Some of those are changeable from the universe_wsgi.ini,
(e.g. files, tmp, beaker_sessions)
but others are not ( job_working_directory, compiled_templates).
Is there a way to change those path ?
I'd like to have the galaxy source code in a completely read-only
location, and all of the runtime files in "/var/galaxy".
However, one the 'galaxy' base directory is read only, I get several
'permission denied' exceptions when I try to use the galaxy server.
Thanks,
Gordon.
1
0