A tool shed admin will now receive content alerts (as part of the alert message) for each file uploaded to a repository that contains either image content or html content if the admin has chosen to receive email alerts for changes to the repository.

This commit is contained in:
Greg Von Kuster
2011-11-15 14:50:08 -05:00
parent 0f98fc6814
commit f12a1c7061
3 changed files with 57 additions and 54 deletions
@@ -26,6 +26,8 @@ Revision: ${revision}
Change description:
${description}
${content_alert_str}
-----------------------------------------------------------------------------
This change alert was sent from the Galaxy tool shed hosted on the server
"${host}"
@@ -520,7 +522,7 @@ def get_configured_ui():
def get_user( trans, id ):
"""Get a user from the database by id"""
return trans.sa_session.query( trans.model.User ).get( trans.security.decode_id( id ) )
def handle_email_alerts( trans, repository ):
def handle_email_alerts( trans, repository, content_alert_str='' ):
repo_dir = repository.repo_path
repo = hg.repository( get_configured_ui(), repo_dir )
smtp_server = trans.app.config.smtp_server
@@ -541,14 +543,25 @@ def handle_email_alerts( trans, repository ):
username = ctx.user().split()[0]
except:
username = ctx.user()
# Build the email message
# We'll use 2 template bodies because we only want to send content
# alerts to tool shed admin users.
admin_body = string.Template( email_alert_template ) \
.safe_substitute( host=trans.request.host,
repository_name=repository.name,
revision='%s:%s' %( str( ctx.rev() ), ctx ),
display_date=display_date,
description=ctx.description(),
username=username,
content_alert_str=content_alert_str )
body = string.Template( email_alert_template ) \
.safe_substitute( host=trans.request.host,
repository_name=repository.name,
revision='%s:%s' %( str( ctx.rev() ), ctx ),
display_date=display_date,
description=ctx.description(),
username=username )
username=username,
content_alert_str='' )
admin_users = trans.app.config.get( "admin_users", "" ).split( "," )
frm = email_from
subject = "Galaxy tool shed repository update alert"
email_alerts = from_json_string( repository.email_alerts )
@@ -556,7 +569,10 @@ def handle_email_alerts( trans, repository ):
to = email.strip()
# Send it
try:
util.send_mail( frm, to, subject, body, trans.app.config )
if to in admin_users:
util.send_mail( frm, to, subject, admin_body, trans.app.config )
else:
util.send_mail( frm, to, subject, body, trans.app.config )
except Exception, e:
log.exception( "An error occurred sending a tool shed repository update alert by email." )
def update_for_browsing( trans, repository, current_working_dir, commit_message='' ):
@@ -567,30 +583,20 @@ def update_for_browsing( trans, repository, current_working_dir, commit_message=
repo = hg.repository( get_configured_ui(), repo_dir )
# The following will delete the disk copy of only the files in the repository.
#os.system( 'hg update -r null > /dev/null 2>&1' )
repo.ui.pushbuffer()
files_to_remove_from_disk = []
files_to_commit = []
commands.status( repo.ui, repo, all=True )
status_and_file_names = repo.ui.popbuffer().strip().split( "\n" )
if status_and_file_names and status_and_file_names[ 0 ] not in [ '' ]:
# status_and_file_names looks something like:
# ['? README', '? tmap_tool/tmap-0.0.9.tar.gz', '? dna_filtering.py', 'C filtering.py', 'C filtering.xml']
# The codes used to show the status of files are:
# M = modified
# A = added
# R = removed
# C = clean
# ! = deleted, but still tracked
# ? = not tracked
# I = ignored
for status_and_file_name in status_and_file_names:
if status_and_file_name.startswith( '?' ) or status_and_file_name.startswith( 'I' ):
files_to_remove_from_disk.append( os.path.abspath( os.path.join( repo_dir, status_and_file_name.split()[1] ) ) )
elif status_and_file_name.startswith( 'M' ) or status_and_file_name.startswith( 'A' ) or status_and_file_name.startswith( 'R' ):
files_to_commit.append( os.path.abspath( os.path.join( repo_dir, status_and_file_name.split()[1] ) ) )
# We may have files on disk in the repo directory that aren't being tracked, so they must be removed.
# We'll use mercurial's purge extension to do this. Using this extension requires the following entry
# in the repository's hgrc file which was not required for some time, so we'll add it if it's missing.
# The codes used to show the status of files are as follows.
# M = modified
# A = added
# R = removed
# C = clean
# ! = deleted, but still tracked
# ? = not tracked
# I = ignored
# We'll use mercurial's purge extension to remove untracked file. Using this extension requires the
# following entry in the repository's hgrc file which was not required for some time, so we'll add it
# if it's missing.
# [extensions]
# hgext.purge=
lines = repo.opener( 'hgrc', 'rb' ).readlines()
@@ -624,9 +630,14 @@ def update_for_browsing( trans, repository, current_working_dir, commit_message=
commit_message = 'Committed changes to: %s' % ', '.join( files_to_commit )
repo.dirstate.write()
repo.commit( user=trans.user.username, text=commit_message )
cmd = 'hg update > /dev/null 2>&1'
os.chdir( repo_dir )
os.system( 'hg update > /dev/null 2>&1' )
proc = subprocess.Popen( args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
return_code = proc.wait()
os.chdir( current_working_dir )
if return_code != 0:
output = proc.stdout.read( 32768 )
log.debug( 'hg update > /dev/null 2>&1 failed in repository directory %s, reason: %s' % ( repo_dir, output ) )
def load_tool( trans, config_file ):
"""
Load a single tool from the file named by `config_file` and return
@@ -101,12 +101,12 @@ class UploadController( BaseUIController ):
full_path = os.path.abspath( os.path.join( repo_dir, upload_point, uploaded_file_filename ) )
else:
full_path = os.path.abspath( os.path.join( repo_dir, uploaded_file_filename ) )
# TODO: enhance this method to set a flag and alert an admin to review content since
# the hard checks are too restrictive.
#ok, message = self.__check_file_content( uploaded_file_name )
#if ok:
# Move the uploaded file to the load_point within the repository hierarchy.
shutil.move( uploaded_file_name, full_path )
if os.path.isfile( full_path ):
content_alert_str = self.__check_file_content( full_path )
else:
content_alert_str = ''
commands.add( repo.ui, repo, full_path )
try:
commands.commit( repo.ui, repo, full_path, user=trans.user.username, message=commit_message )
@@ -128,7 +128,7 @@ class UploadController( BaseUIController ):
# Handle the special case where a xxx.loc.sample file is
# being uploaded by copying it to ~/tool-data/xxx.loc.
copy_sample_loc_file( trans, full_path )
handle_email_alerts( trans, repository )
handle_email_alerts( trans, repository, content_alert_str=content_alert_str )
if ok:
# Update the repository files for browsing.
update_for_browsing( trans, repository, current_working_dir, commit_message=commit_message )
@@ -194,18 +194,7 @@ class UploadController( BaseUIController ):
tar.extractall( path=full_path )
tar.close()
uploaded_file.close()
"""
# TODO: enhance this method to set a flag and alert an admin to review content since
# the hard checks are too restrictive.
for filename_in_archive in filenames_in_archive:
if os.path.isfile( filename_in_archive ):
ok, message = self.__check_file_content( filename_in_archive )
if not ok:
# Refresh the repository files for browsing.
current_working_dir = os.getcwd()
update_for_browsing( trans, repository, current_working_dir )
return False, message, []
"""
content_alert_str = ''
if remove_repo_files_not_in_tar and not repository.is_new:
# We have a repository that is not new (it contains files), so discover
# those files that are in the repository, but not in the uploaded archive.
@@ -250,6 +239,9 @@ class UploadController( BaseUIController ):
# The directory is not empty
pass
for filename_in_archive in filenames_in_archive:
# Check file content to ensure it is appropriate.
if os.path.isfile( filename_in_archive ):
content_alert_str += self.__check_file_content( filename_in_archive )
commands.add( repo.ui, repo, filename_in_archive )
if filename_in_archive.endswith( 'tool_data_table_conf.xml.sample' ):
# Handle the special case where a tool_data_table_conf.xml.sample
@@ -271,7 +263,7 @@ class UploadController( BaseUIController ):
# exception. If this happens, we'll try the following.
repo.dirstate.write()
repo.commit( user=trans.user.username, text=commit_message )
handle_email_alerts( trans, repository )
handle_email_alerts( trans, repository, content_alert_str )
return True, '', files_to_remove
def uncompress( self, repository, uploaded_file_name, uploaded_file_filename, isgzip, isbz2 ):
if isgzip:
@@ -349,15 +341,9 @@ class UploadController( BaseUIController ):
return False, message
return True, ''
def __check_file_content( self, file_path ):
return True, ''
message = ''
ok = True
head, tail = os.path.split( file_path )
if check_html( file_path ):
message = 'The file <b>%s</b> contains HTML content which cannot be uploaded to a Galaxy tool shed.' % str( tail )
ok = False
message = 'The file "%s" contains HTML content.\n' % str( file_path )
elif check_image( file_path ):
# For now we won't allow images to be uploaded.
message = 'The file <b>%s</b> contains image content that cannot be uploaded to a Galaxy tool shed.' % str( tail )
ok = False
return ok, message
message = 'The file "%s" contains image content.\n' % str( file_path )
return message
@@ -64,7 +64,13 @@
<div class="toolForm">
<div class="toolFormTitle">Upload a single file or a tarball</div>
<div class="toolFormBody">
## TODO: nginx
<div class="form-row">
<div class="warningmessage">
Uploading may take a while, depending upon the size of the file. Wait until a message is displayed in your
browser after clicking the <b>Upload</b> button below.
</div>
<div style="clear: both"></div>
</div>
<form id="upload_form" name="upload_form" action="${h.url_for( controller='upload', action='upload', repository_id=trans.security.encode_id( repository.id ) )}" enctype="multipart/form-data" method="post">
<div class="form-row">
<label>File:</label>