1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/84187b357d0c/ changeset: 84187b357d0c user: greg date: 2011-11-22 17:05:38 summary: Enhance User preferences within a Galaxy tool shed to enable users to elect to receive email when content is first uploaded to a new repository. Also add a new grid interface to enable users to easily manage registering with any tool shed respositories to receive email when changes are made to the selected repositories. affected #: 11 files diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/tools/parameters/basic.py --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -166,7 +166,7 @@ """Factory method to create parameter of correct type""" param_name = param.get( "name" ) if not param_name: - raise ValueError( "Tool parameters require a 'name'" ) + raise ValueError( "Tool parameter '%s' requires a 'name'" % (param_name ) ) param_type = param.get("type") if not param_type: raise ValueError( "Tool parameter '%s' requires a 'type'" % ( param_name ) ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/controllers/admin.py --- a/lib/galaxy/webapps/community/controllers/admin.py +++ b/lib/galaxy/webapps/community/controllers/admin.py @@ -475,6 +475,7 @@ kwd[ 'f-Category.name' ] = category.name elif operation == "receive email alerts": if kwd[ 'id' ]: + kwd[ 'caller' ] = 'browse_repositories' return trans.response.send_redirect( web.url_for( controller='repository', action='set_email_alerts', **kwd ) ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/controllers/common.py --- a/lib/galaxy/webapps/community/controllers/common.py +++ b/lib/galaxy/webapps/community/controllers/common.py @@ -12,6 +12,28 @@ log = logging.getLogger( __name__ ) +new_repo_email_alert_template = """ +GALAXY TOOL SHED NEW REPOSITORY ALERT +----------------------------------------------------------------------------- +You received this alert because you registered to receive email when +new repositories were created in the Galaxy tool shed named "${host}". +----------------------------------------------------------------------------- + +Repository name: ${repository_name} +Date content uploaded: ${display_date} +Uploaded by: ${username} + +Revision: ${revision} +Change description: +${description} + +${content_alert_str} + +----------------------------------------------------------------------------- +This change alert was sent from the Galaxy tool shed hosted on the server +"${host}" +""" + email_alert_template = """ GALAXY TOOL SHED REPOSITORY UPDATE ALERT ----------------------------------------------------------------------------- @@ -464,7 +486,7 @@ except Exception, e: invalid_files.append( ( name, str( e ) ) ) return metadata_dict, invalid_files -def set_repository_metadata( trans, id, changeset_revision, **kwd ): +def set_repository_metadata( trans, id, changeset_revision, content_alert_str='', **kwd ): """Set repository metadata""" message = '' status = 'done' @@ -484,6 +506,9 @@ repository_metadata = trans.model.RepositoryMetadata( repository.id, changeset_revision, metadata_dict ) trans.sa_session.add( repository_metadata ) trans.sa_session.flush() + # If this is the first record stored for this repository, see if we need to send any email alerts. + if len( repository.downloadable_revisions ) == 1: + handle_email_alerts( trans, repository, content_alert_str='', new_repo_alert=True, admin_only=False ) else: # Update the last saved repository_metadata table row. repository_metadata = get_latest_repository_metadata( trans, id ) @@ -557,11 +582,31 @@ 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, content_alert_str='' ): +def handle_email_alerts( trans, repository, content_alert_str='', new_repo_alert=False, admin_only=False ): + # There are 2 complementary features that enable a tool shed user to receive email notification: + # 1. Within User Preferences, they can elect to receive email when the first (or first valid) + # change set is produced for a new repository. + # 2. When viewing or managing a repository, they can check the box labeled "Receive email alerts" + # which caused them to receive email alerts when updates to the repository occur. This same feature + # is available on a per-repository basis on the repository grid within the tool shed. + # + # There are currently 4 scenarios for sending email notification when a change is made to a repository: + # 1. An admin user elects to receive email when the first change set is produced for a new repository + # from User Preferences. The change set does not have to include any valid content. This allows for + # the capture of inappropriate content being uploaded to new repositories. + # 2. A regular user elects to receive email when the first valid change set is produced for a new repository + # from User Preferences. This differs from 1 above in that the user will not receive email until a + # change set tha tincludes valid content is produced. + # 3. An admin user checks the "Receive email alerts" check box on the manage repository page. Since the + # user is an admin user, the email will include information about both HTML and image content that was + # included in the change set. + # 4. A regular user checks the "Receive email alerts" check box on the manage repository page. Since the + # user is not an admin user, the email will not include any information about both HTML and image content + # that was included in the change set. repo_dir = repository.repo_path repo = hg.repository( get_configured_ui(), repo_dir ) smtp_server = trans.app.config.smtp_server - if smtp_server and repository.email_alerts: + if smtp_server and ( new_repo_alert or repository.email_alerts ): # Send email alert to users that want them. if trans.app.config.email_from is not None: email_from = trans.app.config.email_from @@ -580,26 +625,40 @@ username = ctx.user() # 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, - content_alert_str='' ) + if new_repo_alert: + template = new_repo_email_alert_template + else: + template = email_alert_template + admin_body = string.Template( 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( 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='' ) 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 ) + if new_repo_alert: + subject = "New Galaxy tool shed repository alert" + email_alerts = [] + for user in trans.sa_session.query( trans.model.User ) \ + .filter( and_( trans.model.User.table.c.deleted == False, + trans.model.User.table.c.new_repo_alert == True ) ): + if admin_only: + if user.email in admin_users: + email_alerts.append( user.email ) + else: + email_alerts.append( user.email ) + else: + subject = "Galaxy tool shed repository update alert" + email_alerts = from_json_string( repository.email_alerts ) for email in email_alerts: to = email.strip() # Send it diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/controllers/repository.py --- a/lib/galaxy/webapps/community/controllers/repository.py +++ b/lib/galaxy/webapps/community/controllers/repository.py @@ -182,6 +182,37 @@ .outerjoin( model.RepositoryCategoryAssociation.table ) \ .outerjoin( model.Category.table ) +class EmailAlertsRepositoryListGrid( RepositoryListGrid ): + columns = [ + RepositoryListGrid.NameColumn( "Name", + key="name", + link=( lambda item: dict( operation="view_or_manage_repository", + id=item.id, + webapp="community" ) ), + attach_popup=False ), + RepositoryListGrid.DescriptionColumn( "Synopsis", + key="description", + attach_popup=False ), + RepositoryListGrid.UserColumn( "Owner", + model_class=model.User, + link=( lambda item: dict( operation="repositories_by_user", id=item.id, webapp="community" ) ), + attach_popup=False, + key="User.username" ), + RepositoryListGrid.EmailAlertsColumn( "Alert", attach_popup=False ), + # Columns that are valid for filtering but are not visible. + grids.DeletedColumn( "Deleted", + key="deleted", + visible=False, + filterable="advanced" ) + ] + operations = [ grids.GridOperation( "Receive email alerts", + allow_multiple=True, + condition=( lambda item: not item.deleted ), + async_compatible=False ) ] + global_actions = [ + grids.GridAction( "User preferences", dict( controller='user', action='index', cntrller='repository', webapp='community' ) ) + ] + class ValidRepositoryListGrid( RepositoryListGrid ): class RevisionColumn( grids.GridColumn ): def __init__( self, col_name ): @@ -290,6 +321,7 @@ matched_repository_list_grid = MatchedRepositoryListGrid() valid_repository_list_grid = ValidRepositoryListGrid() repository_list_grid = RepositoryListGrid() + email_alerts_repository_list_grid = EmailAlertsRepositoryListGrid() category_list_grid = CategoryListGrid() @web.expose @@ -876,6 +908,7 @@ elif operation == "receive email alerts": if trans.user: if kwd[ 'id' ]: + kwd[ 'caller' ] = 'browse_repositories' return trans.response.send_redirect( web.url_for( controller='repository', action='set_email_alerts', **kwd ) ) @@ -1550,7 +1583,9 @@ @web.require_login( "set email alerts" ) def set_email_alerts( self, trans, **kwd ): # Set email alerts for selected repositories - params = util.Params( kwd ) + # This method is called from multiple grids, so + # the caller must be passed. + caller = kwd[ 'caller' ] user = trans.user if user: repository_ids = util.listify( kwd.get( 'id', '' ) ) @@ -1582,9 +1617,63 @@ kwd[ 'status' ] = 'done' del kwd[ 'operation' ] return trans.response.send_redirect( web.url_for( controller='repository', - action='browse_repositories', + action=caller, **kwd ) ) @web.expose + @web.require_login( "manage email alerts" ) + def manage_email_alerts( self, trans, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + new_repo_alert = params.get( 'new_repo_alert', '' ) + new_repo_alert_checked = CheckboxField.is_checked( new_repo_alert ) + user = trans.user + if params.get( 'new_repo_alert_button', False ): + user.new_repo_alert = new_repo_alert_checked + trans.sa_session.add( user ) + trans.sa_session.flush() + if new_repo_alert_checked: + message = 'You will receive email alerts for all new valid tool shed repositories.' + else: + message = 'You will not receive any email alerts for new valid tool shed repositories.' + checked = new_repo_alert_checked or ( user and user.new_repo_alert ) + new_repo_alert_check_box = CheckboxField( 'new_repo_alert', checked=checked ) + email_alert_repositories = [] + for repository in trans.sa_session.query( trans.model.Repository ) \ + .filter( and_( trans.model.Repository.table.c.deleted == False, + trans.model.Repository.table.c.email_alerts != None ) ) \ + .order_by( trans.model.Repository.table.c.name ): + if user.email in repository.email_alerts: + email_alert_repositories.append( repository ) + return trans.fill_template( "/webapps/community/user/manage_email_alerts.mako", + webapp='community', + new_repo_alert_check_box=new_repo_alert_check_box, + email_alert_repositories=email_alert_repositories, + message=message, + status=status ) + @web.expose + @web.require_login( "manage email alerts" ) + def multi_select_email_alerts( self, trans, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + if 'webapp' not in kwd: + kwd[ 'webapp' ] = 'community' + if 'operation' in kwd: + operation = kwd['operation'].lower() + if operation == "receive email alerts": + if trans.user: + if kwd[ 'id' ]: + kwd[ 'caller' ] = 'multi_select_email_alerts' + return trans.response.send_redirect( web.url_for( controller='repository', + action='set_email_alerts', + **kwd ) ) + else: + kwd[ 'message' ] = 'You must be logged in to set email alerts.' + kwd[ 'status' ] = 'error' + del kwd[ 'operation' ] + return self.email_alerts_repository_list_grid( trans, **kwd ) + @web.expose @web.require_login( "set repository metadata" ) def set_metadata( self, trans, id, ctx_str, **kwd ): malicious = kwd.get( 'malicious', '' ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/controllers/upload.py --- a/lib/galaxy/webapps/community/controllers/upload.py +++ b/lib/galaxy/webapps/community/controllers/upload.py @@ -32,6 +32,10 @@ tip = repository.tip file_data = params.get( 'file_data', '' ) url = params.get( 'url', '' ) + # Part of the upload process is sending email notification to those that have registered to + # receive them. One scenario occurs when the first change set is produced for the repository. + # See the handle_email_alerts() method for the definition of the scenarios. + new_repo_alert = repository.is_new if params.get( 'upload_button', False ): current_working_dir = os.getcwd() if file_data == '' and url == '': @@ -87,13 +91,14 @@ tar = None istar = False if istar: - ok, message, files_to_remove = self.upload_tar( trans, - repository, - tar, - uploaded_file, - upload_point, - remove_repo_files_not_in_tar, - commit_message ) + ok, message, files_to_remove, content_alert_str = self.upload_tar( trans, + repository, + tar, + uploaded_file, + upload_point, + remove_repo_files_not_in_tar, + commit_message, + new_repo_alert ) else: if ( isgzip or isbz2 ) and uncompress_file: uploaded_file_filename = self.uncompress( repository, uploaded_file_name, uploaded_file_filename, isgzip, isbz2 ) @@ -131,7 +136,9 @@ # 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, content_alert_str=content_alert_str ) + # See if the content of the change set was valid. + admin_only = len( repository.downloadable_revisions ) != 1 + handle_email_alerts( trans, repository, content_alert_str=content_alert_str, new_repo_alert=new_repo_alert, admin_only=admin_only ) if ok: # Update the repository files for browsing. update_for_browsing( trans, repository, current_working_dir, commit_message=commit_message ) @@ -150,7 +157,7 @@ else: message = 'No changes to repository.' # Set metadata on the repository tip - error_message, status = set_repository_metadata( trans, repository_id, repository.tip, **kwd ) + error_message, status = set_repository_metadata( trans, repository_id, repository.tip, content_alert_str=content_alert_str, **kwd ) if error_message: message = '%s<br/>%s' % ( message, error_message ) return trans.response.send_redirect( web.url_for( controller='repository', @@ -176,16 +183,17 @@ remove_repo_files_not_in_tar=remove_repo_files_not_in_tar, message=message, status=status ) - def upload_tar( self, trans, repository, tar, uploaded_file, upload_point, remove_repo_files_not_in_tar, commit_message ): + def upload_tar( self, trans, repository, tar, uploaded_file, upload_point, remove_repo_files_not_in_tar, commit_message, new_repo_alert ): # Upload a tar archive of files. repo_dir = repository.repo_path repo = hg.repository( get_configured_ui(), repo_dir ) files_to_remove = [] + content_alert_str = '' ok, message = self.__check_archive( tar ) if not ok: tar.close() uploaded_file.close() - return ok, message, files_to_remove + return ok, message, files_to_remove, content_alert_str else: if upload_point is not None: full_path = os.path.abspath( os.path.join( repo_dir, upload_point ) ) @@ -197,7 +205,6 @@ tar.extractall( path=full_path ) tar.close() uploaded_file.close() - 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. @@ -256,7 +263,7 @@ # appending them to the shed's tool_data_table_conf.xml file on disk. error, message = handle_sample_tool_data_table_conf_file( trans, filename_in_archive ) if error: - return False, message, files_to_remove + return False, message, files_to_remove, content_alert_str if filename_in_archive.endswith( '.loc.sample' ): # Handle the special case where a xxx.loc.sample file is # being uploaded by copying it to ~/tool-data/xxx.loc. @@ -269,8 +276,10 @@ # 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, content_alert_str ) - return True, '', files_to_remove + # See if the content of the change set was valid. + admin_only = len( repository.downloadable_revisions ) != 1 + handle_email_alerts( trans, repository, content_alert_str=content_alert_str, new_repo_alert=new_repo_alert, admin_only=admin_only ) + return True, '', files_to_remove, content_alert_str def uncompress( self, repository, uploaded_file_name, uploaded_file_filename, isgzip, isbz2 ): if isgzip: self.__handle_gzip( repository, uploaded_file_name ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/model/__init__.py --- a/lib/galaxy/webapps/community/model/__init__.py +++ b/lib/galaxy/webapps/community/model/__init__.py @@ -20,6 +20,7 @@ self.deleted = False self.purged = False self.username = None + self.new_repo_alert = False def set_password_cleartext( self, cleartext ): """Set 'self.password' to the digest of 'cleartext'.""" self.password = new_secure_hash( text_type=cleartext ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/model/mapping.py --- a/lib/galaxy/webapps/community/model/mapping.py +++ b/lib/galaxy/webapps/community/model/mapping.py @@ -45,6 +45,7 @@ Column( "username", String( 255 ), index=True ), Column( "password", TrimmedString( 40 ), nullable=False ), Column( "external", Boolean, default=False ), + Column( "new_repo_alert", Boolean, default=False ), Column( "deleted", Boolean, index=True, default=False ), Column( "purged", Boolean, index=True, default=False ) ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 lib/galaxy/webapps/community/model/migrate/versions/0010_add_new_repo_alert_column.py --- /dev/null +++ b/lib/galaxy/webapps/community/model/migrate/versions/0010_add_new_repo_alert_column.py @@ -0,0 +1,50 @@ +""" +Migration script to add the new_repo_alert column to the galaxy_user table. +""" + +from sqlalchemy import * +from sqlalchemy.orm import * +from migrate import * +from migrate.changeset import * + +import sys, logging +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 ) +db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) ) + +def upgrade(): + print __doc__ + metadata.reflect() + # Create and initialize imported column in job table. + User_table = Table( "galaxy_user", metadata, autoload=True ) + c = Column( "new_repo_alert", Boolean, default=False, index=True ) + try: + # Create + c.create( User_table ) + assert c is User_table.c.new_repo_alert + # Initialize. + if migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite': + default_false = "0" + elif migrate_engine.name == 'postgres': + default_false = "false" + db_session.execute( "UPDATE galaxy_user SET new_repo_alert=%s" % default_false ) + except Exception, e: + print "Adding new_repo_alert column to the galaxy_user table failed: %s" % str( e ) + log.debug( "Adding new_repo_alert column to the galaxy_user table failed: %s" % str( e ) ) + +def downgrade(): + metadata.reflect() + # Drop new_repo_alert column from galaxy_user table. + User_table = Table( "galaxy_user", metadata, autoload=True ) + try: + User_table.c.new_repo_alert.drop() + except Exception, e: + print "Dropping column new_repo_alert from the galaxy_user table failed: %s" % str( e ) + log.debug( "Dropping column new_repo_alert from the galaxy_user table failed: %s" % str( e ) ) diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 templates/user/index.mako --- a/templates/user/index.mako +++ b/templates/user/index.mako @@ -16,7 +16,7 @@ <li><a href="${h.url_for( controller='user', action='api_keys', cntrller=cntrller )}">${_('Manage your API keys')}</a></li> %endif %if trans.app.config.enable_openid: - <li><a href="${h.url_for( controller='user', action='openid_manage', cntrller=cntrller )}">${ ('Manage OpenIDs')}</a> linked to your account</li> + <li><a href="${h.url_for( controller='user', action='openid_manage', cntrller=cntrller )}">${_('Manage OpenIDs')}</a> linked to your account</li> %endif %if trans.app.config.use_remote_user: %if trans.app.config.remote_user_logout_href: @@ -27,14 +27,18 @@ %endif %else: <li><a href="${h.url_for( controller='user', action='manage_user_info', cntrller=cntrller, webapp='community' )}">${_('Manage your information')}</a></li> + <li><a href="${h.url_for( controller='repository', action='manage_email_alerts', cntrller=cntrller, webapp='community' )}">${_('Manage your email alerts')}</a></li> + <li><a href="${h.url_for( controller='user', action='logout', logout_all=True )}" target="_top">${_('Logout')}</a> ${_('of all user sessions')}</li> %endif </ul> - <p> - You are using <strong>${trans.user.get_disk_usage( nice_size=True )}</strong> of disk space in this Galaxy instance. - %if trans.app.config.enable_quotas: - Your disk quota is: <strong>${trans.app.quota_agent.get_quota( trans.user, nice_size=True )}</strong>. - %endif - </p> + %if webapp == 'galaxy': + <p> + You are using <strong>${trans.user.get_disk_usage( nice_size=True )}</strong> of disk space in this Galaxy instance. + %if trans.app.config.enable_quotas: + Your disk quota is: <strong>${trans.app.quota_agent.get_quota( trans.user, nice_size=True )}</strong>. + %endif + </p> + %endif %else: %if not message: <p>${n_('You are currently not logged in.')}</p> diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 templates/webapps/community/index.mako --- a/templates/webapps/community/index.mako +++ b/templates/webapps/community/index.mako @@ -67,9 +67,6 @@ <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_categories', webapp='community' )}">Browse by category</a></div> - <div class="toolTitle"> - <a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', webapp='community' )}">Browse all repositories</a> - </div> %if trans.user: <div class="toolTitle"><a target="galaxy_main" href="${h.url_for( controller='repository', action='browse_repositories', operation='my_repositories', webapp='community' )}">Browse my repositories</a> diff -r 843fdc5e0ebdc2eafcf97b64c8191b5564ea1836 -r 84187b357d0c6b5bf0c2d9bab5609c10143efb75 templates/webapps/community/user/manage_email_alerts.mako --- /dev/null +++ b/templates/webapps/community/user/manage_email_alerts.mako @@ -0,0 +1,54 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> + +<br/><br/> +<ul class="manage-table-actions"> + <li> + <a class="action-button" href="${h.url_for( controller='repository', action='multi_select_email_alerts', cntrller='repository', webapp=webapp )}">Manage repository alerts</a> + </li> + <li> + <a class="action-button" href="${h.url_for( controller='user', action='index', cntrller='repository', webapp=webapp )}">User preferences</a> + </li> +</ul> + +%if message: + ${render_msg( message, status )} +%endif + +<div class="toolForm"> + <div class="toolFormTitle">Email alerts for new repositories</div> + <form name="new_repo_alert" id="new_repo_alert" action="${h.url_for( controller='repository', action='manage_email_alerts', webapp=webapp )}" method="post" > + <div class="form-row"> + <label>New repository alert:</label> + ${new_repo_alert_check_box.get_html()} + <div class="toolParamHelp" style="clear: both;"> + Check the box and click <b>Save</b> to receive email when the first change set is created for a new repository. + </div> + </div> + <div class="form-row"> + <input type="submit" name="new_repo_alert_button" value="Save"/> + </div> + </form> +</div> +<p/> +%if email_alert_repositories: + <div class="toolForm"> + <div class="toolFormTitle">You are registered to receive email alerts for changes to the following repositories</div> + <div class="form-row"> + <table class="grid"> + <tr> + <th>Name</th> + <th>Description</th> + </tr> + %for repository in email_alert_repositories: + <tr> + <td>${repository.name}</td> + <td>${repository.description}</td> + </tr> + %endfor + </table> + </div> + </div> + <p/> +%endif + Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.