3 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/43bf2d91ca84/ Changeset: 43bf2d91ca84 User: martenson Date: 2014-11-03 20:16:36+00:00 Summary: changes to account updates: added javascript valdiation of username and email changes; user account will be deactivated if you change an email address and you have to activate it once again Affected #: 2 files diff -r db6130ed74cd2186e8646e20a8c94993c114ff1a -r 43bf2d91ca84df43bea0c0dc9c8b5b1e1f4098b6 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -573,7 +573,7 @@ email = trans.user.email if username is None: # User is coming from outside registration form, load email from trans username = trans.user.username - is_activation_sent = self.send_verification_email( trans, email, username) + is_activation_sent = self.send_verification_email( trans, email, username ) if is_activation_sent: message = 'This account has not been activated yet. The activation link has been sent again. Please check your email address <b>%s</b> including the spam/trash folder.<br><a target="_top" href="%s">Return to the home page</a>.' % ( email, url_for( '/' ) ) status = 'error' @@ -819,7 +819,7 @@ def prepare_activation_link( self, trans, email ): """ - Prepares the account activation link for the user. + Prepare the account activation link for the user. """ activation_token = self.get_activation_token( trans, email ) activation_link = url_for( controller='user', action='activate', activation_token=activation_token, email=email, qualified=True ) @@ -827,7 +827,7 @@ 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. + Check for the activation token. Create new activation token and store it in the database if no token 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 @@ -841,7 +841,7 @@ @web.expose def activate( self, trans, **kwd ): """ - Function checks whether token fits the user and then activates the user's account. + Check whether token fits the user and then activate the user's account. """ params = util.Params( kwd, sanitize=False ) email = urllib.unquote( params.get( 'email', None ) ) @@ -849,7 +849,7 @@ if email is None or activation_token is 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" ) + return trans.show_error_message( "You are using an invalid 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() @@ -859,12 +859,12 @@ if user.activation_token == activation_token: user.activation_token = None user.active = True - trans.sa_session.add(user) + 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 trans.show_error_message( "You are using invalid 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 ): @@ -984,6 +984,9 @@ @web.expose def edit_info( self, trans, cntrller, **kwd ): + """ + Edit user information = username, email or password. + """ params = util.Params( kwd ) is_admin = cntrller == 'admin' and trans.user_is_admin() message = util.restore_text( params.get( 'message', '' ) ) @@ -1001,6 +1004,7 @@ # Editing email and username email = util.restore_text( params.get( 'email', '' ) ) username = util.restore_text( params.get( 'username', '' ) ).lower() + # Validate the new values for email and username message = validate_email( trans, email, user ) if not message and username: @@ -1008,15 +1012,32 @@ if message: status = 'error' else: - # The user's private role name must match the user's login ( email ) - private_role = trans.app.security_agent.get_private_user_role( user ) - private_role.name = email - private_role.description = 'Private role for ' + email - # Now change the user info - user.email = email - user.username = username - trans.sa_session.add_all( ( user, private_role ) ) - trans.sa_session.flush() + if ( user.email != email ): + # The user's private role name must match the user's login ( email ) + private_role = trans.app.security_agent.get_private_user_role( user ) + private_role.name = email + private_role.description = 'Private role for ' + email + # Change the email itself + user.email = email + trans.sa_session.add_all( ( user, private_role ) ) + trans.sa_session.flush() + if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on: + user.active = False + trans.sa_session.add( user ) + trans.sa_session.flush() + is_activation_sent = self.send_verification_email( trans, user.email, user.username ) + if is_activation_sent: + message = 'The login information has been updated with the changes.<br>Verification email has been sent to your new email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.' + success = True + else: + message = 'Unable to send activation email, please contact your local Galaxy administrator.' + if trans.app.config.error_email_to is not None: + message += ' Contact: %s' % trans.app.config.error_email_to + success = False + if ( user.username != username ): + user.username = username + trans.sa_session.add( user ) + trans.sa_session.flush() message = 'The login information has been updated with the changes.' elif user and params.get( 'change_password_button', False ): # Editing password. Do not sanitize passwords, so get from kwd @@ -1093,6 +1114,9 @@ @web.expose def reset_password( self, trans, email=None, **kwd ): + """ + Reset the user's password. Send him/her an email with the new password. + """ if trans.app.config.smtp_server is None: return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact your local Galaxy administrator." ) message = util.sanitize_text(util.restore_text( kwd.get( 'message', '' ) )) @@ -1162,7 +1186,7 @@ @web.expose def set_default_permissions( self, trans, cntrller, **kwd ): - """Sets the user's default permissions for the new histories""" + """Set the user's default permissions for the new histories""" params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) diff -r db6130ed74cd2186e8646e20a8c94993c114ff1a -r 43bf2d91ca84df43bea0c0dc9c8b5b1e1f4098b6 templates/user/info.mako --- a/templates/user/info.mako +++ b/templates/user/info.mako @@ -3,6 +3,80 @@ <% is_admin = cntrller == 'admin' and trans.user_is_admin() %><%def name="render_user_info()"> + + <script type="text/javascript"> + $(document).ready(function() { + + function validateString(test_string, type) { + var mail_re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + var username_re = /^[a-z0-9\-]{4,255}$/; + if (type === 'email') { + return mail_re.test(test_string); + } else if (type === 'username'){ + return username_re.test(test_string); + } + } + + function renderError(message) { + $(".donemessage").hide(); + if ($(".errormessage").length === 1) { + $(".errormessage").html(message); + } else { + var div = document.createElement( "div" ); + div.className = "errormessage"; + div.innerHTML = message; + document.body.insertBefore( div, document.body.firstChild ); + } + } + function renderDone(message) { + $(".errormessage").hide(); + if ($(".donemessage").length === 1) { + $(".donemessage").html(message); + } else { + var div = document.createElement( "div" ); + div.className = "donemessage"; + div.innerHTML = message; + document.body.insertBefore( div, document.body.firstChild ); + } + } + + original_email = $( '#email_input' ).val(); + original_username = $( '#name_input' ).val(); + + $( '#login_info' ).bind( 'submit', function( e ) { + var error_text_email= 'Please enter your valid email address.'; + var error_text_email_long= 'Email cannot be more than 255 characters in length.'; + var error_text_username_characters = 'Public name must contain only lowercase letters, numbers and "-". It also has to be shorter than 255 characters but longer than 3.'; + var email = $( '#email_input' ).val(); + var name = $( '#name_input' ).val(); + var validForm = true; + var nothing_changed = ( original_email === email && original_username === name ); + // we need this value to detect submitting at backend + var hidden_input = '<input type="hidden" id="login_info_button" name="login_info_button" value="Submit"/>'; + $( '#send' ).attr( 'disabled', 'disabled' ); + $( "#email_input" ).before( hidden_input ); + + if ( original_email !== email ){ + if ( email.length > 255 ){ renderError( error_text_email_long ); validForm = false; } + else if ( !validateString( email, "email" ) ){ renderError( error_text_email ); validForm = false; } + } + if ( original_username !== name ){ + if ( name && !( validateString( name,"username" ) ) ){ renderError( error_text_username_characters ); validForm = false; } + } + if ( nothing_changed ){ + renderDone( "Nothing has changed." ); + } + if ( !validForm || nothing_changed ) { + e.preventDefault(); + // reactivate the button if the form wasn't submitted + $( '#send' ).removeAttr( 'disabled' ); + } + }); + }); + + </script> + + <h2>Manage User Information</h2> %if not is_admin: <ul class="manage-table-actions"> @@ -16,7 +90,10 @@ <div class="toolFormTitle">Login Information</div><div class="form-row"><label>Email address:</label> - <input type="text" name="email" value="${email}" size="40"/> + <input type="text" id ="email_input" name="email" value="${email}" size="40"/> + <div class="toolParamHelp" style="clear: both;"> + If you change your email address you will receive an activation link in the new mailbox and you have to activate your account by visiting it. + </div></div><div class="form-row"><label>Public name:</label> @@ -37,7 +114,7 @@ </div> %endif %else: - <input type="text" name="username" size="40" value="${username}"/> + <input type="text" id="name_input" name="username" size="40" value="${username}"/><div class="toolParamHelp" style="clear: both;"> Your public name is an optional identifier that will be used to generate addresses for information you share publicly. Public names must be at least four characters in length and contain only lower-case @@ -46,7 +123,7 @@ %endif </div><div class="form-row"> - <input type="submit" name="login_info_button" value="Save"/> + <input type="submit" id="send" name="login_info_button" value="Save"/></div></form></div> https://bitbucket.org/galaxy/galaxy-central/commits/ef99f015a0d2/ Changeset: ef99f015a0d2 User: martenson Date: 2014-11-04 15:26:53+00:00 Summary: gremmar Affected #: 1 file diff -r 43bf2d91ca84df43bea0c0dc9c8b5b1e1f4098b6 -r ef99f015a0d2100e3c3e139ddf3dbf7d5ca6a299 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -864,7 +864,7 @@ 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 invalid 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 trans.show_error_message( "You are using an invalid 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 ): https://bitbucket.org/galaxy/galaxy-central/commits/d53d0150e936/ Changeset: d53d0150e936 User: martenson Date: 2014-11-04 15:27:24+00:00 Summary: Merged in martenson/galaxy-central-marten (pull request #548) changesto user account updates Affected #: 2 files diff -r c7c9023e750ebae364c63345e59f2370f3f0905a -r d53d0150e936944c6a9e10dad1533a9645d37c48 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -573,7 +573,7 @@ email = trans.user.email if username is None: # User is coming from outside registration form, load email from trans username = trans.user.username - is_activation_sent = self.send_verification_email( trans, email, username) + is_activation_sent = self.send_verification_email( trans, email, username ) if is_activation_sent: message = 'This account has not been activated yet. The activation link has been sent again. Please check your email address <b>%s</b> including the spam/trash folder.<br><a target="_top" href="%s">Return to the home page</a>.' % ( email, url_for( '/' ) ) status = 'error' @@ -819,7 +819,7 @@ def prepare_activation_link( self, trans, email ): """ - Prepares the account activation link for the user. + Prepare the account activation link for the user. """ activation_token = self.get_activation_token( trans, email ) activation_link = url_for( controller='user', action='activate', activation_token=activation_token, email=email, qualified=True ) @@ -827,7 +827,7 @@ 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. + Check for the activation token. Create new activation token and store it in the database if no token 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 @@ -841,7 +841,7 @@ @web.expose def activate( self, trans, **kwd ): """ - Function checks whether token fits the user and then activates the user's account. + Check whether token fits the user and then activate the user's account. """ params = util.Params( kwd, sanitize=False ) email = urllib.unquote( params.get( 'email', None ) ) @@ -849,7 +849,7 @@ if email is None or activation_token is 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" ) + return trans.show_error_message( "You are using an invalid 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() @@ -859,12 +859,12 @@ if user.activation_token == activation_token: user.activation_token = None user.active = True - trans.sa_session.add(user) + 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 trans.show_error_message( "You are using an invalid 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 ): @@ -984,6 +984,9 @@ @web.expose def edit_info( self, trans, cntrller, **kwd ): + """ + Edit user information = username, email or password. + """ params = util.Params( kwd ) is_admin = cntrller == 'admin' and trans.user_is_admin() message = util.restore_text( params.get( 'message', '' ) ) @@ -1001,6 +1004,7 @@ # Editing email and username email = util.restore_text( params.get( 'email', '' ) ) username = util.restore_text( params.get( 'username', '' ) ).lower() + # Validate the new values for email and username message = validate_email( trans, email, user ) if not message and username: @@ -1008,15 +1012,32 @@ if message: status = 'error' else: - # The user's private role name must match the user's login ( email ) - private_role = trans.app.security_agent.get_private_user_role( user ) - private_role.name = email - private_role.description = 'Private role for ' + email - # Now change the user info - user.email = email - user.username = username - trans.sa_session.add_all( ( user, private_role ) ) - trans.sa_session.flush() + if ( user.email != email ): + # The user's private role name must match the user's login ( email ) + private_role = trans.app.security_agent.get_private_user_role( user ) + private_role.name = email + private_role.description = 'Private role for ' + email + # Change the email itself + user.email = email + trans.sa_session.add_all( ( user, private_role ) ) + trans.sa_session.flush() + if trans.webapp.name == 'galaxy' and trans.app.config.user_activation_on: + user.active = False + trans.sa_session.add( user ) + trans.sa_session.flush() + is_activation_sent = self.send_verification_email( trans, user.email, user.username ) + if is_activation_sent: + message = 'The login information has been updated with the changes.<br>Verification email has been sent to your new email address. Please verify it by clicking the activation link in the email.<br>Please check your spam/trash folder in case you cannot find the message.' + success = True + else: + message = 'Unable to send activation email, please contact your local Galaxy administrator.' + if trans.app.config.error_email_to is not None: + message += ' Contact: %s' % trans.app.config.error_email_to + success = False + if ( user.username != username ): + user.username = username + trans.sa_session.add( user ) + trans.sa_session.flush() message = 'The login information has been updated with the changes.' elif user and params.get( 'change_password_button', False ): # Editing password. Do not sanitize passwords, so get from kwd @@ -1093,6 +1114,9 @@ @web.expose def reset_password( self, trans, email=None, **kwd ): + """ + Reset the user's password. Send him/her an email with the new password. + """ if trans.app.config.smtp_server is None: return trans.show_error_message( "Mail is not configured for this Galaxy instance. Please contact your local Galaxy administrator." ) message = util.sanitize_text(util.restore_text( kwd.get( 'message', '' ) )) @@ -1162,7 +1186,7 @@ @web.expose def set_default_permissions( self, trans, cntrller, **kwd ): - """Sets the user's default permissions for the new histories""" + """Set the user's default permissions for the new histories""" params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) diff -r c7c9023e750ebae364c63345e59f2370f3f0905a -r d53d0150e936944c6a9e10dad1533a9645d37c48 templates/user/info.mako --- a/templates/user/info.mako +++ b/templates/user/info.mako @@ -3,6 +3,80 @@ <% is_admin = cntrller == 'admin' and trans.user_is_admin() %><%def name="render_user_info()"> + + <script type="text/javascript"> + $(document).ready(function() { + + function validateString(test_string, type) { + var mail_re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + var username_re = /^[a-z0-9\-]{4,255}$/; + if (type === 'email') { + return mail_re.test(test_string); + } else if (type === 'username'){ + return username_re.test(test_string); + } + } + + function renderError(message) { + $(".donemessage").hide(); + if ($(".errormessage").length === 1) { + $(".errormessage").html(message); + } else { + var div = document.createElement( "div" ); + div.className = "errormessage"; + div.innerHTML = message; + document.body.insertBefore( div, document.body.firstChild ); + } + } + function renderDone(message) { + $(".errormessage").hide(); + if ($(".donemessage").length === 1) { + $(".donemessage").html(message); + } else { + var div = document.createElement( "div" ); + div.className = "donemessage"; + div.innerHTML = message; + document.body.insertBefore( div, document.body.firstChild ); + } + } + + original_email = $( '#email_input' ).val(); + original_username = $( '#name_input' ).val(); + + $( '#login_info' ).bind( 'submit', function( e ) { + var error_text_email= 'Please enter your valid email address.'; + var error_text_email_long= 'Email cannot be more than 255 characters in length.'; + var error_text_username_characters = 'Public name must contain only lowercase letters, numbers and "-". It also has to be shorter than 255 characters but longer than 3.'; + var email = $( '#email_input' ).val(); + var name = $( '#name_input' ).val(); + var validForm = true; + var nothing_changed = ( original_email === email && original_username === name ); + // we need this value to detect submitting at backend + var hidden_input = '<input type="hidden" id="login_info_button" name="login_info_button" value="Submit"/>'; + $( '#send' ).attr( 'disabled', 'disabled' ); + $( "#email_input" ).before( hidden_input ); + + if ( original_email !== email ){ + if ( email.length > 255 ){ renderError( error_text_email_long ); validForm = false; } + else if ( !validateString( email, "email" ) ){ renderError( error_text_email ); validForm = false; } + } + if ( original_username !== name ){ + if ( name && !( validateString( name,"username" ) ) ){ renderError( error_text_username_characters ); validForm = false; } + } + if ( nothing_changed ){ + renderDone( "Nothing has changed." ); + } + if ( !validForm || nothing_changed ) { + e.preventDefault(); + // reactivate the button if the form wasn't submitted + $( '#send' ).removeAttr( 'disabled' ); + } + }); + }); + + </script> + + <h2>Manage User Information</h2> %if not is_admin: <ul class="manage-table-actions"> @@ -16,7 +90,10 @@ <div class="toolFormTitle">Login Information</div><div class="form-row"><label>Email address:</label> - <input type="text" name="email" value="${email}" size="40"/> + <input type="text" id ="email_input" name="email" value="${email}" size="40"/> + <div class="toolParamHelp" style="clear: both;"> + If you change your email address you will receive an activation link in the new mailbox and you have to activate your account by visiting it. + </div></div><div class="form-row"><label>Public name:</label> @@ -37,7 +114,7 @@ </div> %endif %else: - <input type="text" name="username" size="40" value="${username}"/> + <input type="text" id="name_input" name="username" size="40" value="${username}"/><div class="toolParamHelp" style="clear: both;"> Your public name is an optional identifier that will be used to generate addresses for information you share publicly. Public names must be at least four characters in length and contain only lower-case @@ -46,7 +123,7 @@ %endif </div><div class="form-row"> - <input type="submit" name="login_info_button" value="Save"/> + <input type="submit" id="send" name="login_info_button" value="Save"/></div></form></div> 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.