initial commit of email activation feature

This commit is contained in:
Martin Cech
2013-09-19 16:38:12 -04:00
parent 59d539a321
commit 3b5d8e5837
12 changed files with 336 additions and 38 deletions
@@ -0,0 +1,9 @@
If you want to disable registration for users that are using disposable email address
rename this file to disposable_email_blacklist.conf and fill it with the disposable domains
that you want to have blacklisted. Each on its own line without the '@' character as shown below.
Users using emails from these domains will get an error during the registration.
mailinator.com
sogetthis.com
spamgourmet.com
trashmail.net
+8
View File
@@ -132,6 +132,14 @@ class Configuration( object ):
self.admin_users = kwargs.get( "admin_users", "" )
self.mailing_join_addr = kwargs.get('mailing_join_addr',"galaxy-announce-join@bx.psu.edu")
self.error_email_to = kwargs.get( 'error_email_to', None )
self.admin_email = kwargs.get( 'admin_email', None )
self.user_activation_on = kwargs.get( 'user_activation_on', None )
self.activation_grace_period = kwargs.get( 'activation_grace_period', None )
self.inactivity_box_visible = kwargs.get( 'inactivity_box_visible', None )
self.inactivity_box_content = kwargs.get( 'inactivity_box_content', None )
self.inactivity_box_class = kwargs.get( 'inactivity_box_class', None )
# Get the disposable email domains blacklist file
self.blacklist_file = resolve_path( kwargs.get( 'blacklist_file', None ), self.root )
self.smtp_server = kwargs.get( 'smtp_server', None )
self.smtp_username = kwargs.get( 'smtp_username', None )
self.smtp_password = kwargs.get( 'smtp_password', None )
+29 -5
View File
@@ -84,12 +84,25 @@ class JobHandlerQueue( object ):
Checks all jobs that are in the 'new', 'queued' or 'running' state in
the database and requeues or cleans up as necessary. Only run as the
job handler starts.
In case the activation is enforced it will filter out the jobs of inactive users.
"""
for job in self.sa_session.query( model.Job ).enable_eagerloads( False ) \
jobs_at_startup = []
if self.app.config.user_activation_on:
jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
.outerjoin( model.User ) \
.filter( ( ( model.Job.state == model.Job.states.NEW ) \
| ( model.Job.state == model.Job.states.RUNNING ) \
| ( model.Job.state == model.Job.states.QUEUED ) ) \
& ( model.Job.handler == self.app.config.server_name ) ):
& ( model.Job.handler == self.app.config.server_name ) \
& or_( ( model.Job.user_id == None ),( model.User.active == True ) ) ).all()
else:
jobs_at_startup = self.sa_session.query( model.Job ).enable_eagerloads( False ) \
.filter( ( ( model.Job.state == model.Job.states.NEW ) \
| ( model.Job.state == model.Job.states.RUNNING ) \
| ( model.Job.state == model.Job.states.QUEUED ) ) \
& ( model.Job.handler == self.app.config.server_name ) ).all()
for job in jobs_at_startup:
if job.tool_id not in self.app.toolbox.tools_by_id:
log.warning( "(%s) Tool '%s' removed from tool config, unable to recover job" % ( job.id, job.tool_id ) )
JobWrapper( job, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator.' )
@@ -146,8 +159,9 @@ class JobHandlerQueue( object ):
over all new and waiting jobs to check the state of the jobs each
depends on. If the job has dependencies that have not finished, it
it goes to the waiting queue. If the job has dependencies with errors,
it is marked as having errors and removed from the queue. Otherwise,
the job is dispatched.
it is marked as having errors and removed from the queue. If the job
belongs to an inactive user it is ignored.
Otherwise, the job is dispatched.
"""
# Pull all new jobs from the queue at once
jobs_to_check = []
@@ -173,7 +187,17 @@ class JobHandlerQueue( object ):
(model.LibraryDatasetDatasetAssociation.deleted == True),
(model.Dataset.state != model.Dataset.states.OK),
(model.Dataset.deleted == True)))).subquery()
jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \
if self.app.config.user_activation_on:
jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \
.outerjoin( model.User ) \
.filter(and_((model.Job.state == model.Job.states.NEW),
or_((model.Job.user_id == None),(model.User.active == True)),
(model.Job.handler == self.app.config.server_name),
~model.Job.table.c.id.in_(hda_not_ready),
~model.Job.table.c.id.in_(ldda_not_ready))) \
.order_by(model.Job.id).all()
else:
jobs_to_check = self.sa_session.query(model.Job).enable_eagerloads(False) \
.filter(and_((model.Job.state == model.Job.states.NEW),
(model.Job.handler == self.app.config.server_name),
~model.Job.table.c.id.in_(hda_not_ready),
+2
View File
@@ -78,6 +78,8 @@ class User( object, Dictifiable ):
self.external = False
self.deleted = False
self.purged = False
self.active = False
self.activation_token = None
self.username = None
# Relationships
self.histories = []
+3 -1
View File
@@ -52,7 +52,9 @@ model.User.table = Table( "galaxy_user", metadata,
Column( "form_values_id", Integer, ForeignKey( "form_values.id" ), index=True ),
Column( "deleted", Boolean, index=True, default=False ),
Column( "purged", Boolean, index=True, default=False ),
Column( "disk_usage", Numeric( 15, 0 ), index=True ) )
Column( "disk_usage", Numeric( 15, 0 ), index=True ) ,
Column( "active", Boolean, index=True, default=True, nullable=False ),
Column( "activation_token", TrimmedString( 64 ), nullable=True, index=True ) )
model.UserAddress.table = Table( "user_address", metadata,
Column( "id", Integer, primary_key=True),
@@ -0,0 +1,57 @@
'''
Created on Sep 10, 2013
@author: marten
Adds 'active' and 'activation_token' columns to the galaxy_user table.
'''
from sqlalchemy import *
from sqlalchemy.orm import *
from migrate import *
from migrate.changeset import *
from galaxy.model.custom_types import TrimmedString
import logging
log = logging.getLogger( __name__ )
user_active_column = Column( "active", Boolean, default=True, nullable=True )
user_activation_token_column = Column( "activation_token", TrimmedString( 64 ), nullable=True )
def display_migration_details():
print ""
print "This migration script adds active and activation_token columns to the user table"
def upgrade(migrate_engine):
print __doc__
metadata = MetaData()
metadata.bind = migrate_engine
metadata.reflect()
# Add the active and activation_token columns to the user table in one try because the depend on each other.
try:
user_table = Table( "galaxy_user", metadata, autoload=True )
user_active_column.create( table = user_table , populate_default = True)
user_activation_token_column.create( table = user_table )
assert user_active_column is user_table.c.active
assert user_activation_token_column is user_table.c.activation_token
except Exception, e:
print str(e)
log.error( "Adding columns 'active' and 'activation_token' to galaxy_user table failed: %s" % str( e ) )
return
def downgrade(migrate_engine):
metadata = MetaData()
metadata.bind = migrate_engine
metadata.reflect()
# Drop the user table's active and activation_token columns in one try because the depend on each other.
try:
user_table = Table( "galaxy_user", metadata, autoload=True )
user_active = user_table.c.active
user_activation_token = user_table.c.activation_token
user_active.drop()
user_activation_token.drop()
except Exception, e:
log.debug( "Dropping 'active' and 'activation_token' columns from galaxy_user table failed: %s" % ( str( e ) ) )
+17 -4
View File
@@ -2,18 +2,31 @@ import re
VALID_PUBLICNAME_RE = re.compile( "^[a-z0-9\-]+$" )
VALID_PUBLICNAME_SUB = re.compile( "[^a-z0-9\-]" )
# Basic regular expression to check email validity.
VALID_EMAIL_RE = re.compile( "[^@]+@[^@]+\.[^@]+" )
FILL_CHAR = '-'
def validate_email( trans, email, user=None, check_dup=True ):
"""
Validates the email format, also checks whether the domain is blacklisted in the disposable domains configuration.
"""
message = ''
# Load the blacklist file location from the configuration file.
blacklist_file = trans.app.config.blacklist_file
if blacklist_file is not None:
email_blacklist = [ line.rstrip() for line in file( blacklist_file ).readlines() ]
if user and user.email == email:
return message
if len( email ) == 0 or "@" not in email or "." not in email:
message = "Enter a real email address"
if not( VALID_EMAIL_RE.match( email ) ):
message = "Please enter your real email address."
elif len( email ) > 255:
message = "Email address exceeds maximum allowable length"
message = "Email address exceeds maximum allowable length."
elif check_dup and trans.sa_session.query( trans.app.model.User ).filter_by( email=email ).first():
message = "User with that email already exists"
message = "User with that email already exists."
# If the blacklist is not empty filter out the disposable domains.
elif email_blacklist is not None:
if email.split('@')[1] in email_blacklist:
message = "Please enter your permanent email address."
return message
def validate_publicname( trans, publicname, user=None ):
+2
View File
@@ -51,6 +51,8 @@ def app_factory( global_conf, **kwargs ):
webapp.add_ui_controllers( 'galaxy.webapps.galaxy.controllers', app )
# Force /history to go to /root/history -- needed since the tests assume this
webapp.add_route( '/history', controller='root', action='history' )
# Force /activate to go to the controller
webapp.add_route( '/activate', controller='user', action='activate' )
# These two routes handle our simple needs at the moment
webapp.add_route( '/async/:tool_id/:data_id/:data_secret', controller='async', action='index', tool_id=None, data_id=None, data_secret=None )
webapp.add_route( '/:controller/:action', action='index' )
+160 -23
View File
@@ -8,6 +8,7 @@ import os
import socket
import string
import random
import urllib
from galaxy import web
from galaxy import util, model
from galaxy.model.orm import and_
@@ -17,6 +18,8 @@ from galaxy.web import url_for
from galaxy.web.base.controller import BaseUIController, UsesFormDefinitionsMixin
from galaxy.web.form_builder import CheckboxField, build_select_field
from galaxy.web.framework.helpers import time_ago, grids
from datetime import datetime, timedelta
from galaxy.util import hash_util
log = logging.getLogger( __name__ )
@@ -147,7 +150,14 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
if trans.user:
if user_openid.user and user_openid.user.id != trans.user.id:
message = "The OpenID <strong>%s</strong> is already associated with another Galaxy account, <strong>%s</strong>. Please disassociate it from that account before attempting to associate it with a new account." % ( display_identifier, user_openid.user.email )
status = "error"
if not trans.user.active and trans.app.config.user_activation_on: # Account activation is ON and the user is INACTIVE.
if ( trans.app.config.activation_grace_period != 0 ): # grace period is ON
if self.is_outside_grace_period( trans, trans.user.create_time ): # User is outside the grace period. Login is disabled and he will have the activation email resent.
message = self.resend_verification_email( trans, trans.user.email )
else: # User is within the grace period, let him log in.
pass
else: # Grace period is off. Login is disabled and user will have the activation email resent.
message = self.resend_verification_email( trans, trans.user.email )
elif not user_openid.user or user_openid.user == trans.user:
if openid_provider_obj.id:
user_openid.provider = openid_provider_obj.id
@@ -282,7 +292,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
subscribe_checked = CheckboxField.is_checked( subscribe )
error = ''
if not trans.app.config.allow_user_creation and not trans.user_is_admin():
error = 'User registration is disabled. Please contact your Galaxy administrator for an account.'
error = 'User registration is disabled. Please contact your local Galaxy administrator for an account.'
else:
# Check email and password validity
error = self.__validate( trans, params, email, password, confirm, username )
@@ -465,9 +475,13 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
openid_providers=trans.app.openid_providers,
form_input_auto_focus=True,
active_view="user" )
def __validate_login( self, trans, **kwd ):
"""
Function validates numerous cases that might happen during the login time.
"""
message = kwd.get( 'message', '' )
status = kwd.get( 'status', 'done' )
status = kwd.get( 'status', 'error' )
email = kwd.get( 'email', '' )
password = kwd.get( 'password', '' )
redirect = kwd.get( 'redirect', trans.request.referer ).strip()
@@ -475,27 +489,69 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first()
if not user:
message = "No such user (please note that login is case sensitive)"
status = 'error'
elif user.deleted:
message = "This account has been marked deleted, contact your Galaxy administrator to restore the account."
status = 'error'
message = "This account has been marked deleted, contact your local Galaxy administrator to restore the account."
if trans.app.config.admin_email is not None:
message += 'Contact: %s' % trans.app.config.admin_email
elif user.external:
message = "This account was created for use with an external authentication method, contact your local Galaxy administrator to activate it."
status = 'error'
if trans.app.config.admin_email is not None:
message += 'Contact: %s' % trans.app.config.admin_email
elif not user.check_password( password ):
message = "Invalid password"
status = 'error'
else:
trans.handle_user_login( user )
if trans.webapp.name == 'galaxy':
trans.log_event( "User logged in" )
message = 'You are now logged in as %s.<br>You can <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
( user.email, redirect, url_for( '/' ) )
if trans.app.config.require_login:
message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( controller="root", action="welcome" )
success = True
elif trans.app.config.user_activation_on and not user.active: # activation is ON and the user is INACTIVE
if ( trans.app.config.activation_grace_period != 0 ): # grace period is ON
if self.is_outside_grace_period( trans, user.create_time ): # User is outside the grace period. Login is disabled and he will have the activation email resent.
message = self.resend_verification_email( trans, email )
else: # User is within the grace period, let him log in.
message, success, status = self.proceed_login( trans, user, redirect )
else: # Grace period is off. Login is disabled and user will have the activation email resent.
message = self.resend_verification_email( trans, email )
else: # activation is OFF
message, success, status = self.proceed_login( trans, user, redirect )
return ( message, status, user, success )
def proceed_login ( self, trans, user, redirect ):
"""
Function processes user login. It is called in case all the login requirements are valid.
"""
trans.handle_user_login( user )
if trans.webapp.name == 'galaxy':
trans.log_event( "User logged in" )
message = 'You are now logged in as %s.<br>You can <a target="_top" href="%s">go back to the page you were visiting</a> or <a target="_top" href="%s">go to the home page</a>.' % \
( user.email, redirect, url_for( '/' ) )
if trans.app.config.require_login:
message += ' <a target="_top" href="%s">Click here</a> to continue to the home page.' % web.url_for( controller="root", action="welcome" )
success = True
status = 'done'
return message, success, status
def resend_verification_email( self, trans, email ):
"""
Function resends the verification email in case user wants to log in with an inactive account.
"""
is_activation_sent = self.send_verification_email( trans, email )
if is_activation_sent:
message = 'This account has not been activated yet. The activation link has been sent again. Please check your email address %s.<br>' % email
else:
message = 'This account has not been activated yet but we are unable to send the activation link. Please contact your local Galaxy administrator.'
if trans.app.config.admin_email is not None:
message += 'Contact: %s' % trans.app.config.admin_email
return message
def is_outside_grace_period ( self, trans, create_time ):
"""
Function checks whether the user is outside the config-defined grace period for inactive accounts.
"""
# Activation is forced and the user is not active yet. Check the grace period.
activation_grace_period = trans.app.config.activation_grace_period
# Default value is 3 hours.
if activation_grace_period == None:
activation_grace_period = 3
delta = timedelta( hours = int( activation_grace_period ) )
time_difference = datetime.utcnow() - create_time
return ( time_difference > delta or activation_grace_period == 0 )
@web.expose
def logout( self, trans, logout_all=False ):
if trans.webapp.name == 'galaxy':
@@ -533,7 +589,9 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
redirect = kwd.get( 'redirect', trans.request.referer ).strip()
is_admin = cntrller == 'admin' and trans.user_is_admin
if not trans.app.config.allow_user_creation and not trans.user_is_admin():
message = 'User registration is disabled. Please contact your Galaxy administrator for an account.'
message = 'User registration is disabled. Please contact your local Galaxy administrator for an account.'
if trans.app.config.admin_email is not None:
message += 'Contact: %s' % trans.app.config.admin_email
status = 'error'
else:
if not refresh_frames:
@@ -606,6 +664,8 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
user = trans.app.model.User( email=email )
user.set_password_cleartext( password )
user.username = username
if trans.app.config.user_activation_on: # Do not set the active flag in case activation is OFF.
user.active = False
trans.sa_session.add( user )
trans.sa_session.flush()
trans.app.security_agent.create_private_user_role( user )
@@ -633,7 +693,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
if subscribe_checked:
# subscribe user to email list
if trans.app.config.smtp_server is None:
error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance."
error = "Now logged in as " + user.email + ". However, subscribing to the mailing list has failed because mail is not configured for this Galaxy instance. <br>Please contact your local Galaxy administrator."
else:
body = 'Join Mailing list.\n'
to = trans.app.config.mailing_join_addr
@@ -659,9 +719,86 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
status = 'error'
success = False
else:
message = 'Now logged in as %s.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
success = True
is_activation_sent = self.send_verification_email( trans, email )
if is_activation_sent:
message = 'Now logged in as %s.<br>Verification email has been sent to your email address. Please verify it by clicking the activation link in the email.<br><a target="_top" href="%s">Return to the home page.</a>' % ( user.email, url_for( '/' ) )
success = True
else:
message = 'Unable to send activation email, please contact your local Galaxy administrator.'
if trans.app.config.admin_email is not None:
message += 'Contact: %s' % trans.app.config.admin_email
success = False
return ( message, status, user, success )
def send_verification_email( self, trans, email ):
"""
Send the verification email containing the activation link to the user's email.
"""
activation_link = self.prepare_activation_link( trans, email )
body = ("Hi %s,\n\n"
"Please click the activation link below in order to activate your account.\n\n"
"Activation link: %s \n\n"
"Your Galaxy Team" % ( email, activation_link ))
to = email
frm = trans.app.config.admin_email
subject = 'How to activate your Galaxy account'
try:
util.send_mail( frm, to, subject, body, trans.app.config )
return True
except:
return False
def prepare_activation_link( self, trans, email ):
"""
Prepares the account activation link for the user.
"""
activation_token = self.get_activation_token( trans, email )
host = trans.request.host.split( ':' )[ 0 ]
if host == 'localhost':
host = socket.getfqdn()
activation_link = str( trans.request.host ) + url_for( controller='user', action='activate' ) + "?activation_token=" + str( activation_token ) + "&email=" + urllib.quote( email )
return activation_link
def get_activation_token ( self, trans, email ):
"""
Checks for the activation token. Creates new activation token and stores it in the database if none found.
"""
user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email == email ).first()
activation_token = user.activation_token
if activation_token == None:
activation_token = hash_util.new_secure_hash( str( random.getrandbits( 256 ) ) )
user.activation_token = activation_token
trans.sa_session.add( user )
trans.sa_session.flush()
return activation_token
@web.expose
def activate( self, trans, **kwd ):
"""
Function checks whether token fits the user and then activates the user's account.
"""
params = util.Params( kwd, sanitize=False )
email = urllib.unquote( params.get( 'email', None ) )
activation_token = params.get( 'activation_token', None )
if email == None or activation_token == None:
# We don't have the email or activation_token, show error.
return trans.show_error_message( "You are using wrong activation link. Try to log-in and we will send you a new activation email.<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller="root", action="index" )
else:
# Find the user
user = trans.sa_session.query( trans.app.model.User ).filter( trans.app.model.User.table.c.email==email ).first()
if user.activation_token == activation_token:
user.activation_token = None
user.active = True
trans.sa_session.add(user)
trans.sa_session.flush()
return trans.show_ok_message( "Your account has been successfully activated!<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller='root', action='index' )
else:
# Tokens don't match. Activation is denied.
return trans.show_error_message( "You are using wrong activation link. Try to log in and we will send you a new activation email.<br><a href='%s'>Go to login page.</a>" ) % web.url_for( controller='root', action='index' )
return
def __get_user_type_form_definition( self, trans, user=None, **kwd ):
params = util.Params( kwd )
if user and user.values:
@@ -885,7 +1022,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
@web.expose
def reset_password( self, trans, email=None, **kwd ):
if trans.app.config.smtp_server is None:
return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact an administrator." )
return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact your local Galaxy administrator." )
message = util.restore_text( kwd.get( 'message', '' ) )
status = 'done'
if kwd.get( 'reset_password_button', False ):
@@ -1042,7 +1179,7 @@ class User( BaseUIController, UsesFormDefinitionsMixin ):
phone = util.restore_text( params.get( 'phone', '' ) )
ok = True
if not trans.app.config.allow_user_creation and not is_admin:
return trans.show_error_message( 'User registration is disabled. Please contact your Galaxy administrator for an account.' )
return trans.show_error_message( 'User registration is disabled. Please contact your local Galaxy administrator for an account.' )
if params.get( 'new_address_button', False ):
if not short_desc:
ok = False
+1
View File
@@ -1140,6 +1140,7 @@ ul.icons{list-style-type:none;text-indent:-0.75em}ul.icons li [class^="fa-icon-"
body{background:#fff;color:#000;margin:10px}body.full-content{overflow:hidden;margin:0;padding:0;width:100%;height:100%}
#background{position:absolute;background:#fff;z-index:-1;top:0;left:0;margin:0;padding:0;width:100%;height:100%}
#messagebox{position:absolute;top:34px;left:0;width:100%;height:30px !important;overflow:hidden;border-bottom:solid #999 1px;font-size:90%}
#inactivebox{position:absolute;top:34px;left:0;width:100%;height:30px !important;overflow:hidden;border-bottom:solid #999 1px;font-size:90%}
#left,#left-border,#center,#right-border,#right{position:absolute;top:34px;bottom:0px;overflow:hidden;background:#fff}
#left{left:0px;width:250px;z-index:200;border-right:solid #999 1px}
#left-border{left:250px}
+19 -3
View File
@@ -4,6 +4,9 @@
self.has_left_panel = hasattr( self, 'left_panel' )
self.has_right_panel = hasattr( self, 'right_panel' )
self.message_box_visible = app.config.message_box_visible
self.show_inactivity_warning = False
if trans.user:
self.show_inactivity_warning = ( ( trans.user.active is False ) and ( app.config.user_activation_on is True) and ( app.config.inactivity_box_content is not None ) )
self.overlay_visible=False
self.active_view=None
self.body_class=""
@@ -26,12 +29,20 @@
right: 0 !important;
%endif
}
%if self.message_box_visible:
## This is some dirty hack happening
%if self.message_box_visible or self.show_inactivity_warning:
#left, #left-border, #center, #right-border, #right
{
top: 64px;
}
%endif
%if self.message_box_visible and self.show_inactivity_warning:
#left, #left-border, #center, #right-border, #right
{
top: 94px;
}
#inactivebox{top:64px;}
%endif
</style>
</%def>
@@ -300,11 +311,16 @@
<div id="masthead" class="navbar navbar-fixed-top navbar-inverse">
${self.masthead()}
</div>
<div id="messagebox" class="panel-${app.config.message_box_class}-message">
%if self.message_box_visible and app.config.message_box_content:
<div id="messagebox" class="panel-${app.config.message_box_class}-message">
${app.config.message_box_content}
%endif
</div>
%endif
%if self.show_inactivity_warning:
<div id="inactivebox" class="panel-warning-message">
${app.config.inactivity_box_content}
</div>
%endif
${self.overlay(visible=self.overlay_visible)}
%if self.has_left_panel:
<div id="left">
+29 -2
View File
@@ -242,8 +242,8 @@ paste.app_factory = galaxy.web.buildapp:app_factory
# Galaxy sends mail for various things: Subscribing users to the mailing list
# if they request it, emailing password resets, notification from the Galaxy
# Sample Tracking system, and reporting dataset errors. To do this, it needs
# to send mail through an SMTP server, which you may define here (host:port).
# Sample Tracking system, reporting dataset errors, and sending activation emails.
# To do this, it needs to send mail through an SMTP server, which you may define here (host:port).
# Galaxy will automatically try STARTTLS but will continue upon failure.
#smtp_server = None
@@ -261,6 +261,33 @@ paste.app_factory = galaxy.web.buildapp:app_factory
# will be sent to this address. Error reports are disabled if no address is set.
#error_email_to = None
# Administrator's email is shown to user in case of Galaxy misconfiguration or a generic error.
# It is also used as a sender for the account activation mail.
#admin_email = None
# E-mail domains blacklist is used for filtering out users that are using disposable email address
# during the registration. If their address domain matches any domain in the BL they are refused the registration.
#blacklist_file = config/disposable_email_blacklist.conf
# -- Account activation
# This is user account activation feature global flag. If set to "False" the rest of the Account
# activation configuration is ignored and user activation is disabled (a.k.a. accounts are active since registration).
# Note the activation is also not working in case the smtp server is not defined.
#user_activation_on = False
# Activation grace period. Activation is not forced (login is not disabled) until
# grace period has passed. Users under grace period can't run jobs (see inactivity_box_content).
# In hours. Default is 3. Enter 0 to disable grace period.
# Users with OpenID logins have grace period forever.
#activation_grace_period = 0
# Used for warning box for inactive accounts (unable to run jobs).
# In use only if activation_grace_period is set.
#inactivity_box_content = Your account has not been activated yet. Please activate your account by verifying your email address. For now you can access everything at Galaxy but your jobs won't run.
# -- Display sites
# Galaxy can display data at various external browsers. These options specify