def check_auto_registration(self, trans, login, password): """ Checks the username/email & password using auth providers in order. If a match is found, returns the 'auto-register' option for that provider. """ if '@' in login: email = login username = None else: email = None username = login for provider, options in self.active_authenticators(email, username, password): if provider is None: log.debug( "Unable to find module: %s" % options ) else: auth_result, auto_email, auto_username = provider.authenticate(email, username, password, options) auto_email = str(auto_email).lower() auto_username = str(auto_username).lower() if auth_result is True: # make username unique if validate_publicname( trans, auto_username ) != '': i = 1 while i <= 10: # stop after 10 tries if validate_publicname( trans, "%s-%i" % (auto_username, i) ) == '': auto_username = "******" % (auto_username, i) break i += 1 else: break # end for loop if we can't make a unique username log.debug( "Email: %s, auto-register with username: %s" % (auto_email, auto_username) ) return (_get_bool(options, 'auto-register', False), auto_email, auto_username) elif auth_result is None: log.debug( "Email: %s, Username %s, stopping due to failed non-continue" % (auto_email, auto_username) ) break # end authentication (skip rest) return (False, '')
def parse_auth_results(trans, auth_results, options): auth_return = {} auth_result, auto_email, auto_username = auth_results[:3] auto_email = str(auto_email).lower() auto_username = str(auto_username).lower() # make username unique if validate_publicname(trans, auto_username) != '': i = 1 while i <= 10: # stop after 10 tries if validate_publicname(trans, "%s-%i" % (auto_username, i)) == '': auto_username = "******" % (auto_username, i) break i += 1 else: raise Conflict("Cannot make unique username") log.debug("Email: %s, auto-register with username: %s" % (auto_email, auto_username)) auth_return["auto_reg"] = string_as_bool( options.get('auto-register', False)) auth_return["email"] = auto_email auth_return["username"] = auto_username auth_return["auto_create_roles"] = string_as_bool( options.get('auto-create-roles', False)) auth_return["auto_create_groups"] = string_as_bool( options.get('auto-create-groups', False)) auth_return["auto_assign_roles_to_groups_only"] = string_as_bool( options.get('auto-assign-roles-to-groups-only', False)) if len(auth_results) == 4: auth_return["attributes"] = auth_results[3] return auth_return
def parse_auth_results(trans, auth_results, options): auth_return = {} auth_result, auto_email, auto_username = auth_results[:3] auto_email = str(auto_email).lower() auto_username = str(auto_username).lower() # make username unique if validate_publicname(trans, auto_username) != '': i = 1 while i <= 10: # stop after 10 tries if validate_publicname(trans, "%s-%i" % (auto_username, i)) == '': auto_username = "******" % (auto_username, i) break i += 1 else: raise Conflict("Cannot make unique username") log.debug("Email: %s, auto-register with username: %s" % (auto_email, auto_username)) auth_return["auto_reg"] = string_as_bool(options.get('auto-register', False)) auth_return["email"] = auto_email auth_return["username"] = auto_username auth_return["auto_create_roles"] = string_as_bool(options.get('auto-create-roles', False)) auth_return["auto_create_groups"] = string_as_bool(options.get('auto-create-groups', False)) auth_return["auto_assign_roles_to_groups_only"] = string_as_bool( options.get('auto-assign-roles-to-groups-only', False)) if len(auth_results) == 4: auth_return["attributes"] = auth_results[3] return auth_return
def check_auto_registration(self, trans, email, password): """ Checks the email/password using auth providers in order. If a match is found, returns the 'auto-register' option for that provider. """ for provider, options in self.active_authenticators(email, password): if provider is None: log.debug( "Unable to find module: %s" % options ) else: auth_result, auto_username = provider.authenticate(email, password, options) auto_username = str(auto_username).lower() if auth_result is True: # make username unique if validate_publicname( trans, auto_username ) != '': i = 1 while i <= 10: # stop after 10 tries if validate_publicname( trans, "%s-%i" % (auto_username, i) ) == '': auto_username = "******" % (auto_username, i) break i += 1 else: break # end for loop if we can't make a unique username log.debug( "Email: %s, auto-register with username: %s" % (email, auto_username) ) return (_get_bool(options, 'auto-register', False), auto_username) elif auth_result is None: log.debug( "Email: %s, stopping due to failed non-continue" % (email) ) break # end authentication (skip rest) return (False, '')
def __validate(self, trans, email, password, confirm, username): if username in ['repos']: return "The term '%s' is a reserved word in the Tool Shed, so it cannot be used as a public user name." % username message = "\n".join([validate_email(trans, email), validate_password(trans, password, confirm), validate_publicname(trans, username)]).rstrip() return message
def edit_username(self, trans, cntrller, **kwd): params = util.Params(kwd) is_admin = cntrller == 'admin' and trans.user_is_admin() message = util.restore_text(params.get('message', '')) status = params.get('status', 'done') user_id = params.get('user_id', None) if user_id and is_admin: user = trans.sa_session.query(trans.app.model.User).get( trans.security.decode_id(user_id)) else: user = trans.user if user and params.get('change_username_button', False): username = kwd.get('username', '') if username: message = validate_publicname(trans, username, user) if message: status = 'error' else: user.username = username trans.sa_session.add(user) trans.sa_session.flush() message = 'The username has been updated with the changes.' return trans.fill_template('/webapps/tool_shed/user/username.mako', cntrller=cntrller, user=user, username=user.username, message=message, status=status)
def register(self, trans, email=None, username=None, password=None, confirm=None, subscribe=False): """ Register a new user. """ if not trans.app.config.allow_user_creation and not trans.user_is_admin: message = "User registration is disabled. Please contact your local Galaxy administrator for an account." if trans.app.config.error_email_to is not None: message += " Contact: %s" % trans.app.config.error_email_to return None, message if not email or not username or not password or not confirm: return None, "Please provide email, username and password." message = "\n".join([validate_email(trans, email), validate_password(trans, password, confirm), validate_publicname(trans, username)]).rstrip() if message: return None, message email = util.restore_text(email) username = util.restore_text(username) message, status = trans.app.auth_manager.check_registration_allowed(email, username, password) if message: return None, message if subscribe: message = self.send_subscription_email(email) if message: return None, message user = self.create(email=email, username=username, password=password) if self.app.config.user_activation_on: self.send_activation_email(trans, email, username) return user, None
def __autoregistration(self, trans, login, password): """ Does the autoregistration if enabled. Returns a message """ try: autoreg = trans.app.auth_manager.check_auto_registration(trans, login, password) except Conflict as conflict: return "Auto-registration failed, {}".format(conflict), None user = None if autoreg["auto_reg"]: email = autoreg["email"] username = autoreg["username"] message = " ".join([validate_email(trans, email, allow_empty=True), validate_publicname(trans, username)]).rstrip() if not message: user = self.user_manager.create(email=email, username=username, password="") if trans.app.config.user_activation_on: self.user_manager.send_activation_email(trans, email, username) # The handle_user_login() method has a call to the history_set_default_permissions() method # (needed when logging in with a history), user needs to have default permissions set before logging in if not trans.user_is_admin: trans.handle_user_login(user) trans.log_event("User (auto) created a new account") trans.log_event("User logged in") if "attributes" in autoreg and "roles" in autoreg["attributes"]: self.__handle_role_and_group_auto_creation( trans, user, autoreg["attributes"]["roles"], auto_create_groups=autoreg["auto_create_groups"], auto_create_roles=autoreg["auto_create_roles"], auto_assign_roles_to_groups_only=autoreg["auto_assign_roles_to_groups_only"]) else: message = "Auto-registration failed, contact your local Galaxy administrator. %s" % message else: message = "No such user or invalid password." return message, user
def create(self, trans, payload, **kwd): """ POST /api/users Creates a new Galaxy user. """ if not trans.app.config.allow_user_creation and not trans.user_is_admin: raise exceptions.ConfigDoesNotAllowException( 'User creation is not allowed in this Galaxy instance') if trans.app.config.use_remote_user and trans.user_is_admin: user = trans.get_or_create_remote_user( remote_user_email=payload['remote_user_email']) elif trans.user_is_admin: username = payload['username'] email = payload['email'] password = payload['password'] message = "\n".join((validate_email(trans, email), validate_password(trans, password, password), validate_publicname(trans, username))).rstrip() if message: raise exceptions.RequestParameterInvalidException(message) else: user = self.user_manager.create(email=email, username=username, password=password) else: raise exceptions.NotImplemented() item = user.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float }) return item
def edit_username( self, trans, cntrller, **kwd ): params = util.Params( kwd ) is_admin = cntrller == 'admin' and trans.user_is_admin() message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) user_id = params.get( 'user_id', None ) if user_id and is_admin: user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) ) else: user = trans.user if user and params.get( 'change_username_button', False ): username = kwd.get( 'username', '' ) if username: message = validate_publicname( trans, username, user ) if message: status = 'error' else: user.username = username trans.sa_session.add( user ) trans.sa_session.flush() message = 'The username has been updated with the changes.' return trans.fill_template( '/webapps/tool_shed/user/username.mako', cntrller=cntrller, user=user, username=user.username, message=message, status=status )
def __validate(self, trans, email, password, confirm, username): message = "\n".join([ validate_email(trans, email), validate_password(trans, password, confirm), validate_publicname(trans, username) ]).rstrip() return message
def create( self, trans, payload, **kwd ): """ POST /api/users Creates a new Galaxy user. """ if not trans.app.config.allow_user_creation and not trans.user_is_admin(): raise exceptions.ConfigDoesNotAllowException( 'User creation is not allowed in this Galaxy instance' ) if trans.app.config.use_remote_user and trans.user_is_admin(): user = trans.get_or_create_remote_user( remote_user_email=payload['remote_user_email'] ) elif trans.user_is_admin(): username = payload[ 'username' ] email = payload[ 'email' ] password = payload[ 'password' ] message = "\n".join( [ validate_email( trans, email ), validate_password( trans, password, password ), validate_publicname( trans, username ) ] ).rstrip() if message: raise exceptions.RequestParameterInvalidException( message ) else: user = self.create_user( trans=trans, email=email, username=username, password=password ) else: raise exceptions.NotImplemented() item = user.to_dict( view='element', value_mapper={ 'id': trans.security.encode_id, 'total_disk_usage': float } ) return item
def deserialize_username(self, item, key, username, trans=None, **context): # TODO: validate_user_input requires trans and should(?) raise exceptions # move validation to UserValidator and use self.app, exceptions instead validation_error = validate_user_input.validate_publicname(trans, username, user=item) if validation_error: raise base.ModelDeserializingError(validation_error) return self.default_deserializer(item, key, username, trans=trans, **context)
def set_public_username(self, trans, id, username, **kwargs): """ Set user's public username and delegate to sharing() """ user = trans.get_user() # message from validate_publicname does not contain input, no need # to escape. message = validate_publicname(trans, username, user) if message: return trans.fill_template("/workflow/sharing.mako", item=self.get_item(trans, id), message=message, status="error") user.username = username trans.sa_session.flush() return self.sharing(trans, id, **kwargs)
def __validate( self, trans, email, password, confirm, username ): if not username: return "A public user name is required in the Tool Shed." if username in [ 'repos' ]: return "The term <b>%s</b> is a reserved word in the Tool Shed, so it cannot be used as a public user name." % username message = validate_email( trans, email ) if not message: message = validate_password( trans, password, confirm ) if not message and username: message = validate_publicname( trans, username ) return message
def set_information(self, trans, id, payload={}, **kwd): """ PUT /api/users/{id}/information/inputs Save a user's email, username, addresses etc. :param id: the encoded id of the user :type id: str :param payload: data with new settings :type payload: dict """ user = self._get_user(trans, id) # Update email if 'email' in payload: email = payload.get('email') message = self._validate_email(email) or validate_email( trans, email, user) if message: raise exceptions.RequestParameterInvalidException(message) if user.email != email: # Update user email and user's private role name which must match private_role = trans.app.security_agent.get_private_user_role( user) private_role.name = email private_role.description = 'Private role for ' + email user.email = email trans.sa_session.add(user) trans.sa_session.add(private_role) trans.sa_session.flush() if trans.app.config.user_activation_on: # Deactivate the user if email was changed and activation is on. user.active = False if self.user_manager.send_activation_email( trans, user.email, user.username): 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.' 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 raise exceptions.InternalServerError(message) # Update public name if 'username' in payload: username = payload.get('username') message = self._validate_publicname( username) or validate_publicname(trans, username, user) if message: raise exceptions.RequestParameterInvalidException(message) if user.username != username: user.username = username # Update user custom form user_info_form_id = payload.get('info|form_id') if user_info_form_id: prefix = 'info|' user_info_form = trans.sa_session.query( trans.app.model.FormDefinition).get( trans.security.decode_id(user_info_form_id)) user_info_values = {} for item in payload: if item.startswith(prefix): user_info_values[item[len(prefix):]] = payload[item] form_values = trans.model.FormValues(user_info_form, user_info_values) trans.sa_session.add(form_values) user.values = form_values # Update values for extra user preference items extra_user_pref_data = dict() extra_pref_keys = self._get_extra_user_preferences(trans) if extra_pref_keys is not None: for key in extra_pref_keys: key_prefix = key + '|' for item in payload: if item.startswith(key_prefix): # Show error message if the required field is empty if payload[item] == "": # Raise an exception when a required field is empty while saving the form keys = item.split("|") section = extra_pref_keys[keys[0]] for input in section['inputs']: if input['name'] == keys[1] and input[ 'required']: raise exceptions.ObjectAttributeMissingException( "Please fill the required field") extra_user_pref_data[item] = payload[item] user.preferences["extra_user_preferences"] = json.dumps( extra_user_pref_data) # Update user addresses address_dicts = {} address_count = 0 for item in payload: match = re.match(r'^address_(?P<index>\d+)\|(?P<attribute>\S+)', item) if match: groups = match.groupdict() index = int(groups['index']) attribute = groups['attribute'] address_dicts[index] = address_dicts.get(index) or {} address_dicts[index][attribute] = payload[item] address_count = max(address_count, index + 1) user.addresses = [] for index in range(0, address_count): d = address_dicts[index] if d.get('id'): try: user_address = trans.sa_session.query( trans.app.model.UserAddress).get( trans.security.decode_id(d['id'])) except Exception as e: raise exceptions.ObjectNotFound( 'Failed to access user address ({}). {}'.format( d['id'], e)) else: user_address = trans.model.UserAddress() trans.log_event('User address added') for field in AddressField.fields(): if str(field[2]).lower() == 'required' and not d.get(field[0]): raise exceptions.ObjectAttributeMissingException( 'Address {}: {} ({}) required.'.format( index + 1, field[1], field[0])) setattr(user_address, field[0], str(d.get(field[0], ''))) user_address.user = user user.addresses.append(user_address) trans.sa_session.add(user_address) trans.sa_session.add(user) trans.sa_session.flush() trans.log_event('User information added') return {'message': 'User information has been saved.'}
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', '' ) ) status = params.get( 'status', 'done' ) user_id = params.get( 'user_id', None ) if user_id and is_admin: user = trans.sa_session.query( trans.app.model.User ).get( trans.security.decode_id( user_id ) ) elif user_id and ( not trans.user or trans.user.id != trans.security.decode_id( user_id ) ): message = 'Invalid user id' status = 'error' user = None else: user = trans.user if user and params.get( 'login_info_button', False ): # 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: message = validate_publicname( trans, username, user ) if message: status = 'error' else: 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.' 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 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( 'edit_user_info_button', False ): # Edit user information - webapp MUST BE 'galaxy' user_type_fd_id = params.get( 'user_type_fd_id', 'none' ) if user_type_fd_id not in [ 'none' ]: user_type_form_definition = trans.sa_session.query( trans.app.model.FormDefinition ).get( trans.security.decode_id( user_type_fd_id ) ) elif user.values: user_type_form_definition = user.values.form_definition else: # User was created before any of the user_info forms were created user_type_form_definition = None if user_type_form_definition: values = self.get_form_values( trans, user, user_type_form_definition, **kwd ) else: values = {} flush_needed = False if user.values: # Editing the user info of an existing user with existing user info user.values.content = values trans.sa_session.add( user.values ) flush_needed = True elif values: form_values = trans.model.FormValues( user_type_form_definition, values ) trans.sa_session.add( form_values ) user.values = form_values flush_needed = True if flush_needed: trans.sa_session.add( user ) trans.sa_session.flush() message = "The user information has been updated with the changes." if user and trans.webapp.name == 'galaxy' and is_admin: kwd[ 'user_id' ] = trans.security.encode_id( user.id ) kwd[ 'id' ] = user_id if message: kwd[ 'message' ] = util.sanitize_text( message ) if status: kwd[ 'status' ] = status return trans.response.send_redirect( web.url_for( controller='user', action='manage_user_info', cntrller=cntrller, **kwd ) )
def set_information(self, trans, id, payload={}, **kwd): """ POST /api/users/{id}/information Save a user's email, username, addresses etc. :param id: the encoded id of the user :type id: str :param payload: data with new settings :type payload: dict """ user = self._get_user(trans, id) email = payload.get('email') username = payload.get('username') if email or username: message = self._validate_email_publicname( email, username) or validate_email(trans, email, user) if not message and username: message = validate_publicname(trans, username, user) if message: raise MessageException(message) if user.email != email: # Update user email and user's private role name which must match private_role = trans.app.security_agent.get_private_user_role( user) private_role.name = email private_role.description = 'Private role for ' + email user.email = email trans.sa_session.add(user) trans.sa_session.add(private_role) trans.sa_session.flush() if trans.app.config.user_activation_on: # Deactivate the user if email was changed and activation is on. user.active = False if self.send_verification_email(trans, user.email, user.username): 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.' 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 raise MessageException(message) if user.username != username: # Update public name user.username = username # Update user custom form user_info_form_id = payload.get('info|form_id') if user_info_form_id: prefix = 'info|' user_info_form = trans.sa_session.query( trans.app.model.FormDefinition).get( trans.security.decode_id(user_info_form_id)) user_info_values = {} for item in payload: if item.startswith(prefix): user_info_values[item[len(prefix):]] = payload[item] form_values = trans.model.FormValues(user_info_form, user_info_values) trans.sa_session.add(form_values) user.values = form_values # Update user addresses address_dicts = {} address_count = 0 for item in payload: match = re.match(r'^address_(?P<index>\d+)\|(?P<attribute>\S+)', item) if match: groups = match.groupdict() index = int(groups['index']) attribute = groups['attribute'] address_dicts[index] = address_dicts.get(index) or {} address_dicts[index][attribute] = payload[item] address_count = max(address_count, index + 1) user.addresses = [] for index in range(0, address_count): d = address_dicts[index] if d.get('id'): try: user_address = trans.sa_session.query( trans.app.model.UserAddress).get( trans.security.decode_id(d['id'])) except Exception as e: raise MessageException( 'Failed to access user address (%s). %s' % (d['id'], e)) else: user_address = trans.model.UserAddress() trans.log_event('User address added') for field in AddressField.fields(): if str(field[2]).lower() == 'required' and not d.get(field[0]): raise MessageException('Address %s: %s (%s) required.' % (index + 1, field[1], field[0])) setattr(user_address, field[0], str(d.get(field[0], ''))) user_address.user = user user.addresses.append(user_address) trans.sa_session.add(user_address) trans.sa_session.add(user) trans.sa_session.flush() trans.log_event('User information added') return {'message': 'User information has been saved.'}
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', '')) status = params.get('status', 'done') user_id = params.get('user_id', None) if user_id and is_admin: user = trans.sa_session.query(trans.app.model.User).get( trans.security.decode_id(user_id)) elif user_id and (not trans.user or trans.user.id != trans.security.decode_id(user_id)): message = 'Invalid user id' status = 'error' user = None else: user = trans.user if user and params.get('login_info_button', False): # 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: message = validate_publicname(trans, username, user) if message: status = 'error' else: 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.' 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 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('edit_user_info_button', False): # Edit user information - webapp MUST BE 'galaxy' user_type_fd_id = params.get('user_type_fd_id', 'none') if user_type_fd_id not in ['none']: user_type_form_definition = trans.sa_session.query( trans.app.model.FormDefinition).get( trans.security.decode_id(user_type_fd_id)) elif user.values: user_type_form_definition = user.values.form_definition else: # User was created before any of the user_info forms were created user_type_form_definition = None if user_type_form_definition: values = self.get_form_values(trans, user, user_type_form_definition, **kwd) else: values = {} flush_needed = False if user.values: # Editing the user info of an existing user with existing user info user.values.content = values trans.sa_session.add(user.values) flush_needed = True elif values: form_values = trans.model.FormValues(user_type_form_definition, values) trans.sa_session.add(form_values) user.values = form_values flush_needed = True if flush_needed: trans.sa_session.add(user) trans.sa_session.flush() message = "The user information has been updated with the changes." if user and trans.webapp.name == 'galaxy' and is_admin: kwd['user_id'] = trans.security.encode_id(user.id) kwd['id'] = user_id if message: kwd['message'] = util.sanitize_text(message) if status: kwd['status'] = status return trans.response.send_redirect( web.url_for(controller='user', action='manage_user_info', cntrller=cntrller, **kwd))
def set_information(self, trans, id, payload={}, **kwd): """ POST /api/users/{id}/information Save a user's email, username, addresses etc. :param id: the encoded id of the user :type id: str :param payload: data with new settings :type payload: dict """ user = self._get_user(trans, id) email = payload.get('email') username = payload.get('username') if email or username: message = self._validate_email_publicname(email, username) or validate_email(trans, email, user) if not message and username: message = validate_publicname(trans, username, user) if message: raise MessageException(message) if user.email != email: # Update user email and user's private role name which must match private_role = trans.app.security_agent.get_private_user_role(user) private_role.name = email private_role.description = 'Private role for ' + email user.email = email trans.sa_session.add(user) trans.sa_session.add(private_role) trans.sa_session.flush() if trans.app.config.user_activation_on: # Deactivate the user if email was changed and activation is on. user.active = False if self.send_verification_email(trans, user.email, user.username): 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.' 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 raise MessageException(message) if user.username != username: # Update public name user.username = username # Update user custom form user_info_form_id = payload.get('info|form_id') if user_info_form_id: prefix = 'info|' user_info_form = trans.sa_session.query(trans.app.model.FormDefinition).get(trans.security.decode_id(user_info_form_id)) user_info_values = {} for item in payload: if item.startswith(prefix): user_info_values[item[len(prefix):]] = payload[item] form_values = trans.model.FormValues(user_info_form, user_info_values) trans.sa_session.add(form_values) user.values = form_values # Update values for extra user preference items extra_user_pref_data = dict() get_extra_pref_keys = self._get_extra_user_preferences(trans) if get_extra_pref_keys is not None: for key in get_extra_pref_keys: key_prefix = key + '|' for item in payload: if item.startswith(key_prefix): # Show error message if the required field is empty if payload[item] == "": # Raise an exception when a required field is empty while saving the form keys = item.split("|") section = get_extra_pref_keys[keys[0]] for input in section['inputs']: if input['name'] == keys[1] and input['required']: raise MessageException("Please fill the required field") extra_user_pref_data[item] = payload[item] user.preferences["extra_user_preferences"] = json.dumps(extra_user_pref_data) # Update user addresses address_dicts = {} address_count = 0 for item in payload: match = re.match(r'^address_(?P<index>\d+)\|(?P<attribute>\S+)', item) if match: groups = match.groupdict() index = int(groups['index']) attribute = groups['attribute'] address_dicts[index] = address_dicts.get(index) or {} address_dicts[index][attribute] = payload[item] address_count = max(address_count, index + 1) user.addresses = [] for index in range(0, address_count): d = address_dicts[index] if d.get('id'): try: user_address = trans.sa_session.query(trans.app.model.UserAddress).get(trans.security.decode_id(d['id'])) except Exception as e: raise MessageException('Failed to access user address (%s). %s' % (d['id'], e)) else: user_address = trans.model.UserAddress() trans.log_event('User address added') for field in AddressField.fields(): if str(field[2]).lower() == 'required' and not d.get(field[0]): raise MessageException('Address %s: %s (%s) required.' % (index + 1, field[1], field[0])) setattr(user_address, field[0], str(d.get(field[0], ''))) user_address.user = user user.addresses.append(user_address) trans.sa_session.add(user_address) trans.sa_session.add(user) trans.sa_session.flush() trans.log_event('User information added') return {'message': 'User information has been saved.'}