details: http://www.bx.psu.edu/hg/galaxy/rev/a5e19a623de5 changeset: 3710:a5e19a623de5 user: Greg Von Kuster <greg@bx.psu.edu> date: Wed Apr 28 11:50:17 2010 -0400 description: More fixes and cleanup for the community space: require public user name when registering, move the category management to the edit form, add the submit for approval feature, move the upload tool button to the left manu since it cannot be secured in the grid, a few other miscellaneous items. diffstat: lib/galaxy/web/controllers/user.py | 3 + lib/galaxy/webapps/community/controllers/common.py | 73 ++++----- lib/galaxy/webapps/community/controllers/tool.py | 3 - lib/galaxy/webapps/community/controllers/upload.py | 2 +- lib/galaxy/webapps/community/model/__init__.py | 28 +++- templates/user/register.mako | 2 +- templates/webapps/community/index.mako | 22 +- templates/webapps/community/tool/edit_tool.mako | 116 +++++++++++++-- templates/webapps/community/tool/manage_categories.mako | 71 --------- templates/webapps/community/tool/view_tool.mako | 10 +- templates/webapps/community/upload/upload.mako | 5 +- 11 files changed, 178 insertions(+), 157 deletions(-) diffs (502 lines): diff -r fe5fa72fdbef -r a5e19a623de5 lib/galaxy/web/controllers/user.py --- a/lib/galaxy/web/controllers/user.py Tue Apr 27 19:01:44 2010 -0400 +++ b/lib/galaxy/web/controllers/user.py Wed Apr 28 11:50:17 2010 -0400 @@ -319,6 +319,9 @@ error = "Passwords do not match" return error def __validate( self, trans, params, email, password, confirm, username, webapp ): + # If coming from the community webapp, we'll require a public user name + if webapp == 'community' and not username: + return "A public user name is required" error = self.__validate_email( trans, email ) if not error: error = self.__validate_password( trans, password, confirm ) diff -r fe5fa72fdbef -r a5e19a623de5 lib/galaxy/webapps/community/controllers/common.py --- a/lib/galaxy/webapps/community/controllers/common.py Tue Apr 27 19:01:44 2010 -0400 +++ b/lib/galaxy/webapps/community/controllers/common.py Wed Apr 28 11:50:17 2010 -0400 @@ -21,19 +21,49 @@ status='error' ) ) tool = get_tool( trans, id ) if params.get( 'edit_tool_button', False ): - tool.user_description = util.restore_text( params.description ) + if params.get( 'in_categories', False ): + in_categories = [ trans.sa_session.query( trans.app.model.Category ).get( x ) for x in util.listify( params.in_categories ) ] + trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=in_categories ) + else: + # There must not be any categories associated with the tool + trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=[] ) + if params.get( 'description', False ): + tool.user_description = util.restore_text( params.get( 'description', '' ) ) trans.sa_session.add( tool ) trans.sa_session.flush() + message="Tool '%s' description and category associations have been saved" % tool.name return trans.response.send_redirect( web.url_for( controller='common', action='edit_tool', cntrller=cntrller, id=id, - message="The information was updated", + message=message, status='done' ) ) + elif params.get( 'approval_button', False ): + # Move the state from NEW to WAITING + event = trans.app.model.Event( state=trans.app.model.Tool.states.WAITING ) + tea = trans.app.model.ToolEventAssociation( tool, event ) + trans.sa_session.add_all( ( event, tea ) ) + trans.sa_session.flush() + message = "Tool '%s' has been submitted for approval and can no longer be modified" % ( tool.name ) + return trans.response.send_redirect( web.url_for( controller='common', + action='view_tool', + cntrller=cntrller, + id=id, + message=message, + status='done' ) ) + in_categories = [] + out_categories = [] + for category in get_categories( trans ): + if category in [ x.category for x in tool.categories ]: + in_categories.append( ( category.id, category.name ) ) + else: + out_categories.append( ( category.id, category.name ) ) return trans.fill_template( '/webapps/community/tool/edit_tool.mako', cntrller=cntrller, + tool=tool, id=id, - tool=tool, + in_categories=in_categories, + out_categories=out_categories, message=message, status=status ) @web.expose @@ -56,43 +86,6 @@ message=message, status=status ) @web.expose - def manage_categories( self, trans, cntrller, **kwd ): - params = util.Params( kwd ) - message = util.restore_text( params.get( 'message', '' ) ) - status = params.get( 'status', 'done' ) - id = params.get( 'id', None ) - if not id: - return trans.response.send_redirect( web.url_for( controller=cntrller, - action='browse_tools', - message='Select a tool to manage categories', - status='error' ) ) - tool = get_tool( trans, id ) - if params.get( 'manage_categories_button', False ): - in_categories = [ trans.sa_session.query( trans.app.model.Category ).get( x ) for x in util.listify( params.in_categories ) ] - trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=in_categories ) - trans.sa_session.refresh( tool ) - message = "Tool '%s' has been updated with %d associated categories" % ( tool.name, len( in_categories ) ) - trans.response.send_redirect( web.url_for( controller='common', - action='manage_categories', - cntrller=cntrller, - id=id, - message=util.sanitize_text( message ), - status=status ) ) - in_categories = [] - out_categories = [] - for category in get_categories( trans ): - if category in [ x.category for x in tool.categories ]: - in_categories.append( ( category.id, category.name ) ) - else: - out_categories.append( ( category.id, category.name ) ) - return trans.fill_template( '/webapps/community/tool/manage_categories.mako', - tool=tool, - in_categories=in_categories, - out_categories=out_categories, - cntrller=cntrller, - message=message, - status=status ) - @web.expose def upload_new_tool_version( self, trans, cntrller, **kwd ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) diff -r fe5fa72fdbef -r a5e19a623de5 lib/galaxy/webapps/community/controllers/tool.py --- a/lib/galaxy/webapps/community/controllers/tool.py Tue Apr 27 19:01:44 2010 -0400 +++ b/lib/galaxy/webapps/community/controllers/tool.py Wed Apr 28 11:50:17 2010 -0400 @@ -82,9 +82,6 @@ key="free-text-search", visible=False, filterable="standard" ) ) - global_actions = [ - grids.GridAction( "Upload tool", dict( controller='upload', action='upload', type='tool' ) ) - ] operations = [ grids.GridOperation( "Download tool", condition=( lambda item: not item.deleted ), diff -r fe5fa72fdbef -r a5e19a623de5 lib/galaxy/webapps/community/controllers/upload.py --- a/lib/galaxy/webapps/community/controllers/upload.py Tue Apr 27 19:01:44 2010 -0400 +++ b/lib/galaxy/webapps/community/controllers/upload.py Wed Apr 28 11:50:17 2010 -0400 @@ -54,7 +54,7 @@ tca = trans.app.model.ToolCategoryAssociation( obj, category ) trans.sa_session.add( tca ) # Initialize the tool event - event = trans.app.model.Event( trans.app.model.Tool.states.NEW ) + event = trans.app.model.Event( state=trans.app.model.Tool.states.NEW ) tea = trans.app.model.ToolEventAssociation( obj, event ) trans.sa_session.add_all( ( event, tea ) ) trans.sa_session.flush() diff -r fe5fa72fdbef -r a5e19a623de5 lib/galaxy/webapps/community/model/__init__.py --- a/lib/galaxy/webapps/community/model/__init__.py Tue Apr 27 19:01:44 2010 -0400 +++ b/lib/galaxy/webapps/community/model/__init__.py Wed Apr 28 11:50:17 2010 -0400 @@ -132,12 +132,18 @@ self.user_id = datatype_bunch.user.id def state( self ): if self.events: - return self.events[0].event.state + # Sort the events in ascending order by update_time + events = sort_by_attr( [ tca.event for tca in self.events ], 'update_time' ) + # Get the last event that occurred + return events[-1].state return None def last_comment( self ): if self.events: - if self.events[0].comment: - return self.events[0].comment + # Sort the events in ascending order by update_time + events = sort_by_attr( [ tca.event for tca in self.events ], 'update_time' ) + # Get the last event that occurred + if events[-1].comment: + return events[-1].comment else: return '' return 'No comment' @@ -228,6 +234,22 @@ ## ---- Utility methods ------------------------------------------------------- +def sort_by_attr( seq, attr ): + """ + Sort the sequence of objects by object's attribute + Arguments: + seq - the list or any sequence (including immutable one) of objects to sort. + attr - the name of attribute to sort by + """ + # Use the "Schwartzian transform" + # Create the auxiliary list of tuples where every i-th tuple has form + # (seq[i].attr, i, seq[i]) and sort it. The second item of tuple is needed not + # only to provide stable sorting, but mainly to eliminate comparison of objects + # (which can be expensive or prohibited) in case of equal attribute values. + intermed = map( None, map( getattr, seq, ( attr, ) * len( seq ) ), xrange( len( seq ) ), seq ) + intermed.sort() + return map( operator.getitem, intermed, ( -1, ) * len( intermed ) ) + def directory_hash_id( id ): s = str( id ) l = len( s ) diff -r fe5fa72fdbef -r a5e19a623de5 templates/user/register.mako --- a/templates/user/register.mako Tue Apr 27 19:01:44 2010 -0400 +++ b/templates/user/register.mako Wed Apr 28 11:50:17 2010 -0400 @@ -67,7 +67,7 @@ <label>Public user name:</label> <input type="text" name="username" size="40" value="${username}"/> <div class="toolParamHelp" style="clear: both;"> - Your user name is an optional identifier that will be used to generate addresses for information + Your user name is an identifier that will be used to generate addresses for information you share publicly. User names must be at least four characters in length and contain only lower-case letters, numbers, and the '-' character. </div> diff -r fe5fa72fdbef -r a5e19a623de5 templates/webapps/community/index.mako --- a/templates/webapps/community/index.mako Tue Apr 27 19:01:44 2010 -0400 +++ b/templates/webapps/community/index.mako Wed Apr 28 11:50:17 2010 -0400 @@ -28,18 +28,20 @@ <span>Tools</span> </div> <div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='tool', action='browse_tools' )}" target="galaxy_main">Browse tools</a></div> - </div> - </div> - <div class="toolSectionPad"></div> - <div class="toolSectionTitle"> - <span>Forum</span> + <div class="toolSectionBg"> + <div class="toolTitle"><a href="${h.url_for( controller='tool', action='browse_tools' )}" target="galaxy_main">Browse tools</a></div> + </div> </div> <div class="toolSectionBody"> - <div class="toolSectionBg"> - <div class="toolTitle"><a href="${h.url_for( controller='forum', action='browse_forums' )}" target="galaxy_main">Forums</a></div> - </div> + <div class="toolSectionBg"> + <div class="toolTitle"> + %if trans.user: + <a href="${h.url_for( controller='upload', action='upload', type='tool' )}" target="galaxy_main">Upload a tool</a> + %else: + Login to upload + %endif + </div> + </div> </div> </div> </div> diff -r fe5fa72fdbef -r a5e19a623de5 templates/webapps/community/tool/edit_tool.mako --- a/templates/webapps/community/tool/edit_tool.mako Tue Apr 27 19:01:44 2010 -0400 +++ b/templates/webapps/community/tool/edit_tool.mako Wed Apr 28 11:50:17 2010 -0400 @@ -1,3 +1,4 @@ +<%inherit file="/base.mako"/> <%namespace file="/message.mako" import="render_msg" /> <%! @@ -9,6 +10,39 @@ %> <%inherit file="${inherit(context)}"/> +<%def name="javascripts()"> + ${parent.javascripts()} + <script type="text/javascript"> + $(function(){ + $("input:text:first").focus(); + }) + </script> +</%def> + +<%def name="render_select( name, options )"> + <select name="${name}" id="${name}" style="min-width: 250px; height: 150px;" multiple> + %for option in options: + <option value="${option[0]}">${option[1]}</option> + %endfor + </select> +</%def> + +<script type="text/javascript"> +$().ready(function() { + $('#categories_add_button').click(function() { + return !$('#out_categories option:selected').remove().appendTo('#in_categories'); + }); + $('#categories_remove_button').click(function() { + return !$('#in_categories option:selected').remove().appendTo('#out_categories'); + }); + $('form#edit_tool').submit(function() { + $('#in_categories option').each(function(i) { + $(this).attr("selected", "selected"); + }); + }); +}); +</script> + <%def name="title()">Edit Tool</%def> <h2>Edit ${tool.name} <em>${tool.description}</em></h2> @@ -17,37 +51,77 @@ ${render_msg( message, status )} %endif -<form id="edit_tool" name="edit_tool" action="${h.url_for( controller='common', action='edit_tool' )}" method="post"> - <input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/> - <input type="hidden" name="cntrller" value="${cntrller}"/> +%if cntrller == 'admin' or ( tool.is_new() and trans.user == tool.user ): <div class="toolForm"> <div class="toolFormTitle">${tool.name} <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a> <div popupmenu="tool-${tool.id}-popup"> + <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a> <a class="action-button" href="${h.url_for( controller='common', action='manage_categories', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Manage categories</a> <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a> <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a> </div> </div> - <div class="toolFormBody"> - <div class="form-row"> - <label>Description:</label> - <div class="form-row-input"><textarea name="description" rows="5" cols="35">${tool.user_description}</textarea></div> - <div style="clear: both"></div> + <form id="edit_tool" name="edit_tool" action="${h.url_for( controller='common', action='edit_tool' )}" method="post"> + <div class="toolFormBody"> + <input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/> + <input type="hidden" name="cntrller" value="${cntrller}"/> + <div class="form-row"> + <label>Tool Id:</label> + ${tool.tool_id} + <div style="clear: both"></div> + </div> + <div class="form-row"> + <label>Version:</label> + ${tool.version} + <div style="clear: both"></div> + </div> + <div class="form-row"> + <label>Description:</label> + <div class="form-row-input"><textarea name="description" rows="5" cols="35">${tool.user_description}</textarea></div> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" id="edit_tool_button" name="edit_tool_button" value="Save"> + </div> </div> - <div class="form-row"> - <label>Tool Id:</label> - ${tool.tool_id} - <div style="clear: both"></div> + <div class="toolFormTitle">Manage categories</div> + <div class="toolFormBody"> + <div class="form-row"> + <div style="float: left; margin-right: 10px;"> + <label>Categories associated with '${tool.name}'</label> + ${render_select( "in_categories", in_categories )}<br/> + <input type="submit" id="categories_remove_button" value=">>"/> + </div> + <div> + <label>Categories not associated with '${tool.name}'</label> + ${render_select( "out_categories", out_categories )}<br/> + <input type="submit" id="categories_add_button" value="<<"/> + </div> + </div> + <div class="form-row"> + <input type="submit" id="edit_tool_button" name="edit_tool_button" value="Save"/> + </div> </div> - <div class="form-row"> - <label>Version:</label> - ${tool.version} - <div style="clear: both"></div> + </form> + %if tool.is_new(): + <div class="toolFormTitle">Get approval for publishing</div> + <div class="toolFormBody"> + <form name="get_approval" id="get_approval" action="${h.url_for( controller='common', action='edit_tool' )}" method="post" > + <input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/> + <input type="hidden" name="cntrller" value="${cntrller}"/> + <div class="form-row"> + <input type="submit" name="approval_button" value="Submit for approval"/> + </div> + <div class="toolParamHelp" style="clear: both;"> + Tools must be approved before they are made available to others in the community. After you have submitted + your tool to be published, you will no longer be able to modify it, so make sure to save the information in + each of the forms above before submitting for approval. + </div> + </form> </div> - <div class="form-row"> - <input type="submit" class="primary-button" name="edit_tool_button" value="Save"> - </div> - </div> + %endif </div> -</form> +%else: + ${render_msg( "You are not allowed to edit this tool", "error" )} +%endif diff -r fe5fa72fdbef -r a5e19a623de5 templates/webapps/community/tool/manage_categories.mako --- a/templates/webapps/community/tool/manage_categories.mako Tue Apr 27 19:01:44 2010 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -<%inherit file="/base.mako"/> -<%namespace file="/message.mako" import="render_msg" /> - -<%def name="javascripts()"> - ${parent.javascripts()} - <script type="text/javascript"> - $(function(){ - $("input:text:first").focus(); - }) - </script> -</%def> - -<%def name="render_select( name, options )"> - <select name="${name}" id="${name}" style="min-width: 250px; height: 150px;" multiple> - %for option in options: - <option value="${option[0]}">${option[1]}</option> - %endfor - </select> -</%def> - -<script type="text/javascript"> -$().ready(function() { - $('#categories_add_button').click(function() { - return !$('#out_categories option:selected').remove().appendTo('#in_categories'); - }); - $('#categories_remove_button').click(function() { - return !$('#in_categories option:selected').remove().appendTo('#out_categories'); - }); - $('form#associate_tool_category').submit(function() { - $('#in_categories option').each(function(i) { - $(this).attr("selected", "selected"); - }); - }); -}); -</script> - -%if message: - ${render_msg( message, status )} -%endif - -<div class="toolForm"> - <div class="toolFormTitle">Tool ${tool.name} - <a id="tool-${tool.id}-popup" class="popup-arrow" style="display: none;">▼</a> - <div popupmenu="tool-${tool.id}-popup"> - <a class="action-button" href="${h.url_for( controller='common', action='view_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">View information</a> - <a class="action-button" href="${h.url_for( controller='common', action='edit_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Edit information</a> - <a class="action-button" href="${h.url_for( controller='common', action='upload_new_tool_version', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">Upload a new version</a> - <a class="action-button" href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">Download tool</a> - </div> - </div> - <div class="toolFormBody"> - <form name="associate_tool_category" id="associate_tool_category" action="${h.url_for( controller='common', action='manage_categories', id=trans.security.encode_id( tool.id ) )}" method="post" > - <input name="cntrller" type="hidden" value="${cntrller}" size=40"/> - <div class="form-row"> - <div style="float: left; margin-right: 10px;"> - <label>Categories associated with '${tool.name}'</label> - ${render_select( "in_categories", in_categories )}<br/> - <input type="submit" id="categories_remove_button" value=">>"/> - </div> - <div> - <label>Categories not associated with '${tool.name}'</label> - ${render_select( "out_categories", out_categories )}<br/> - <input type="submit" id="categories_add_button" value="<<"/> - </div> - </div> - <div class="form-row"> - <input type="submit" name="manage_categories_button" value="Save"/> - </div> - </form> - </div> -</div> diff -r fe5fa72fdbef -r a5e19a623de5 templates/webapps/community/tool/view_tool.mako --- a/templates/webapps/community/tool/view_tool.mako Tue Apr 27 19:01:44 2010 -0400 +++ b/templates/webapps/community/tool/view_tool.mako Wed Apr 28 11:50:17 2010 -0400 @@ -38,11 +38,6 @@ </div> <div class="toolFormBody"> <div class="form-row"> - <label>Description:</label> - ${tool.user_description} - <div style="clear: both"></div> - </div> - <div class="form-row"> <label>Tool Id:</label> ${tool.tool_id} <div style="clear: both"></div> @@ -53,6 +48,11 @@ <div style="clear: both"></div> </div> <div class="form-row"> + <label>Description:</label> + ${tool.user_description} + <div style="clear: both"></div> + </div> + <div class="form-row"> <label>Uploaded by:</label> ${tool.user.username} <div style="clear: both"></div> diff -r fe5fa72fdbef -r a5e19a623de5 templates/webapps/community/upload/upload.mako --- a/templates/webapps/community/upload/upload.mako Tue Apr 27 19:01:44 2010 -0400 +++ b/templates/webapps/community/upload/upload.mako Wed Apr 28 11:50:17 2010 -0400 @@ -48,7 +48,7 @@ <div class="form-row"> <label>Category</label> <div class="form-row-input"> - <select name="category_id"> + <select name="category_id" multiple> %for category in categories: %if category.id in selected_categories: <option value="${trans.security.encode_id( category.id )}" selected>${category.name}</option> @@ -76,6 +76,7 @@ </div> <div class="toolHelp"> <div class="toolHelpBody"> - <p><strong>Tool Files</strong></p> + <p><strong>Creating tool files</strong></p> + <p>Help coming...</p> </div> </div>