details: http://www.bx.psu.edu/hg/galaxy/rev/054527415fac changeset: 3697:054527415fac user: Nate Coraor <nate@bx.psu.edu> date: Mon Apr 26 15:40:52 2010 -0400 description: Community app: Add the "view tool" interface and make tools downloadable. diffstat: lib/galaxy/webapps/community/config.py | 3 + lib/galaxy/webapps/community/controllers/tool_browser.py | 53 +++++++++++++- lib/galaxy/webapps/community/controllers/upload.py | 1 + lib/galaxy/webapps/community/datatypes/__init__.py | 2 +- lib/galaxy/webapps/community/model/__init__.py | 31 ++++++++- static/images/silk/page_white_compressed.png | 0 templates/webapps/community/tool/edit_tool.mako | 2 +- templates/webapps/community/tool/view_tool.mako | 49 +++++++++++++ 8 files changed, 134 insertions(+), 7 deletions(-) diffs (261 lines): diff -r 5002f66739e1 -r 054527415fac lib/galaxy/webapps/community/config.py --- a/lib/galaxy/webapps/community/config.py Mon Apr 26 13:53:48 2010 -0400 +++ b/lib/galaxy/webapps/community/config.py Mon Apr 26 15:40:52 2010 -0400 @@ -62,6 +62,9 @@ self.log_events = False self.cloud_controller_instance = False self.datatypes_config = kwargs.get( 'datatypes_config_file', 'community_datatypes_conf.xml' ) + # Proxy features + self.apache_xsendfile = kwargs.get( 'apache_xsendfile', False ) + self.nginx_x_accel_redirect_base = kwargs.get( 'nginx_x_accel_redirect_base', False ) # Parse global_conf and save the parser global_conf = kwargs.get( 'global_conf', None ) global_conf_parser = ConfigParser.ConfigParser() diff -r 5002f66739e1 -r 054527415fac lib/galaxy/webapps/community/controllers/tool_browser.py --- a/lib/galaxy/webapps/community/controllers/tool_browser.py Mon Apr 26 13:53:48 2010 -0400 +++ b/lib/galaxy/webapps/community/controllers/tool_browser.py Mon Apr 26 15:40:52 2010 -0400 @@ -1,4 +1,4 @@ -import sys, os, operator, string, shutil, re, socket, urllib, time, logging +import sys, os, operator, string, shutil, re, socket, urllib, time, logging, mimetypes from galaxy.web.base.controller import * from galaxy.webapps.community import model @@ -31,7 +31,7 @@ NameColumn( "Name", key="name", model_class=model.Tool, - link=( lambda item: dict( operation="Edit Tool", id=item.id, webapp="community" ) ), + link=( lambda item: dict( operation="View Tool", id=item.id, webapp="community" ) ), attach_popup=False, filterable="advanced" ), # Columns that are valid for filtering but are not visible. @@ -79,6 +79,10 @@ return trans.response.send_redirect( web.url_for( controller='tool_browser', action='browse_tool', **kwargs ) ) + elif operation == "view tool": + return trans.response.send_redirect( web.url_for( controller='tool_browser', + action='view_tool', + **kwargs ) ) elif operation == "edit tool": return trans.response.send_redirect( web.url_for( controller='tool_browser', action='edit_tool', @@ -95,6 +99,25 @@ message=message, status=status ) @web.expose + def view_tool( self, trans, id=None, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + # Get the tool + tool = None + if id is not None: + id = trans.app.security.decode_id( id ) + tool = trans.sa_session.query( trans.model.Tool ).get( id ) + if tool is None: + return trans.response.send_redirect( web.url_for( controller='tool_browser', + action='browse_tools', + message='Please select a Tool to edit (the tool ID provided was invalid)', + status='error' ) ) + return trans.fill_template( '/webapps/community/tool/view_tool.mako', + tool=tool, + message=message, + status=status ) + @web.expose def edit_tool( self, trans, id=None, **kwd ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) @@ -102,7 +125,6 @@ # Get the tool tool = None if id is not None: - encoded_id = id id = trans.app.security.decode_id( id ) tool = trans.sa_session.query( trans.model.Tool ).get( id ) if tool is None: @@ -110,6 +132,11 @@ action='browse_tools', message='Please select a Tool to edit (the tool ID provided was invalid)', status='error' ) ) + if tool.user_id != trans.user.id: + return trans.response.send_redirect( web.url_for( controller='tool_browser', + action='view_tool', + message='You are not the owner of this tool and therefore cannot edit it', + status='error' ) ) if params.save_button and ( params.file_data != '' or params.url != '' ): # TODO: call the upload method in the upload controller. message = 'Uploading new version not implemented' @@ -126,8 +153,26 @@ status='done' ) ) categories = trans.sa_session.query( trans.model.Category ).order_by( trans.model.Category.table.c.name ).all() return trans.fill_template( '/webapps/community/tool/edit_tool.mako', - encoded_id = encoded_id, tool=tool, categories=categories, message=message, status=status ) + @web.expose + def download_tool( self, trans, id=None, **kwd ): + params = util.Params( kwd ) + tool = None + # Get the tool + tool = None + if id is not None: + id = trans.app.security.decode_id( id ) + tool = trans.sa_session.query( trans.model.Tool ).get( id ) + if tool is None: + return trans.response.send_redirect( web.url_for( controller='tool_browser', + action='browse_tools', + message='Please select a Tool to edit (the tool ID provided was invalid)', + status='error' ) ) + + trans.response.set_content_type(tool.mimetype) + trans.response.headers['Content-Length'] = int( os.stat( tool.file_name ).st_size ) + trans.response.headers['Content-Disposition'] = 'attachment; filename=%s' % tool.download_file_name + return open( tool.file_name ) diff -r 5002f66739e1 -r 054527415fac lib/galaxy/webapps/community/controllers/upload.py --- a/lib/galaxy/webapps/community/controllers/upload.py Mon Apr 26 13:53:48 2010 -0400 +++ b/lib/galaxy/webapps/community/controllers/upload.py Mon Apr 26 15:40:52 2010 -0400 @@ -51,6 +51,7 @@ shutil.copy( uploaded_file.name, obj.file_name ) return trans.response.send_redirect( web.url_for( controller='tool_browser', action='edit_tool', + id=trans.app.security.encode_id( obj.id ), message='Uploaded %s' % meta.message, status='done' ) ) except datatypes.DatatypeVerificationError, e: diff -r 5002f66739e1 -r 054527415fac lib/galaxy/webapps/community/datatypes/__init__.py --- a/lib/galaxy/webapps/community/datatypes/__init__.py Mon Apr 26 13:53:48 2010 -0400 +++ b/lib/galaxy/webapps/community/datatypes/__init__.py Mon Apr 26 15:40:52 2010 -0400 @@ -99,7 +99,7 @@ def verify( self, file ): msg = '' try: - tar = tarfile.TarFile( fileobj = file ) + tar = tarfile.open( file.name ) except tarfile.ReadError: raise DatatypeVerificationError( 'The tool file is not a readable tar file' ) xml_names = filter( lambda x: x.lower().endswith( '.xml' ), tar.getnames() ) diff -r 5002f66739e1 -r 054527415fac lib/galaxy/webapps/community/model/__init__.py --- a/lib/galaxy/webapps/community/model/__init__.py Mon Apr 26 13:53:48 2010 -0400 +++ b/lib/galaxy/webapps/community/model/__init__.py Mon Apr 26 15:40:52 2010 -0400 @@ -4,7 +4,7 @@ Naming: try to use class names that have a distinct plural form so that the relationship cardinalities are obvious (e.g. prefer Dataset to Data) """ -import os.path, os, errno, sys, codecs, operator, tempfile, logging, tarfile +import os.path, os, errno, sys, codecs, operator, tempfile, logging, tarfile, mimetypes from galaxy.util.bunch import Bunch from galaxy import util from galaxy.util.hash_util import * @@ -96,6 +96,7 @@ self.version = version or "1.0.0" self.user_id = user_id self.external_filename = external_filename + self.__extension = None def get_file_name( self ): if not self.external_filename: assert self.id is not None, "ID must be set before filename used (commit the object)" @@ -132,6 +133,34 @@ if not isinstance( category, Category ): category = trans.sa_session.query( Category ).get( int( category ) ) self.categories.append( ToolCategoryAssociation( self, category ) ) + @property + def extension( self ): + # if instantiated via a query, this unmapped property won't exist + if '_Tool__extension' not in dir( self ): + self.__extension = None + if self.__extension is None: + head = open( self.file_name, 'rb' ).read( 4 ) + try: + assert head[:3] == 'BZh' + assert int( head[-1] ) in range( 0, 10 ) + self.__extension = 'tar.bz2' + except AssertionError: + pass + if self.__extension is None: + try: + assert head[:2] == '\037\213' + self.__extension = 'tar.gz' + except: + pass + if self.__extension is None: + self.__extension = 'tar' + return self.__extension + @property + def download_file_name( self ): + return '%s_%s.%s' % ( self.tool_id, self.version, self.extension ) + @property + def mimetype( self ): + return mimetypes.guess_type( self.download_file_name )[0] class Tag ( object ): def __init__( self, id=None, type=None, parent_id=None, name=None ): diff -r 5002f66739e1 -r 054527415fac static/images/silk/page_white_compressed.png Binary file static/images/silk/page_white_compressed.png has changed diff -r 5002f66739e1 -r 054527415fac templates/webapps/community/tool/edit_tool.mako --- a/templates/webapps/community/tool/edit_tool.mako Mon Apr 26 13:53:48 2010 -0400 +++ b/templates/webapps/community/tool/edit_tool.mako Mon Apr 26 15:40:52 2010 -0400 @@ -18,7 +18,7 @@ %endif <form id="tool_edit_form" name="tool_edit_form" action="${h.url_for( controller='tool_browser', action='edit_tool' )}" enctype="multipart/form-data" method="post"> -<input type="hidden" name="id" value="${encoded_id}"/> +<input type="hidden" name="id" value="${trans.app.security.encode_id( tool.id )}"/> <div class="toolForm"> <div class="toolFormTitle">Edit Tool</div> <div class="toolFormBody"> diff -r 5002f66739e1 -r 054527415fac templates/webapps/community/tool/view_tool.mako --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/webapps/community/tool/view_tool.mako Mon Apr 26 15:40:52 2010 -0400 @@ -0,0 +1,49 @@ +<%namespace file="/message.mako" import="render_msg" /> + +<%! + def inherit(context): + if context.get('use_panels'): + return '/webapps/community/base_panels.mako' + else: + return '/base.mako' +%> +<%inherit file="${inherit(context)}"/> + +<%def name="title()">View Tool</%def> + +%if message: + ${render_msg( message, status )} +%endif + +<div class="toolForm"> + <div class="toolFormTitle">${tool.name} <em>${tool.description}</em> ${tool.version} (ID: ${tool.tool_id})</div> + <div class="toolFormBody"> + <div class="form-row"> + Uploaded by <a href="${h.url_for(controller='tool_browser', action='user_tools')}">${tool.user.username}</a> on ${tool.create_time.strftime('%B %d, %Y')} + <div style="clear: both"></div> + </div> + <div class="form-row"> + <label>Categories:</label> + %for category in [ tca.category for tca in tool.categories ]: + ${category.name} + %endfor + <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>Download:</label> + <a href="${h.url_for(controller='tool_browser', action='download_tool', id=trans.app.security.encode_id( tool.id ))}"><img src="${h.url_for('/static/images/silk/page_white_compressed.png')}"> ${tool.tool_id}_${tool.version}</a> + <div style="clear: both"></div> + </div> + %if trans.user.id == tool.user_id: + <div class="form-row"> + <em>This is your tool. You may <a href="${h.url_for(controller='tool_browser', action='edit_tool', id=trans.app.security.encode_id( tool.id ) )}">edit it</a>.</em> + <div style="clear: both"></div> + </div> + %endif + </div> +</div>