Example #1
0
 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
Example #2
0
 def send_reset_email(self, trans, payload={}, **kwd):
     """Reset the user's password. Send an email with token that allows a password change."""
     if self.app.config.smtp_server is None:
         return "Mail is not configured for this Galaxy instance and password reset information cannot be sent. Please contact your local Galaxy administrator."
     email = payload.get("email")
     if not email:
         return "Please provide your email."
     message = validate_email(trans, email, check_dup=False)
     if message:
         return message
     else:
         reset_user, prt = self.get_reset_token(trans, email)
         if prt:
             host = self.__get_host(trans)
             reset_url = url_for(controller='root',
                                 action='login',
                                 token=prt.token)
             body = PASSWORD_RESET_TEMPLATE % (
                 host,
                 prt.expiration_time.strftime(
                     trans.app.config.pretty_datetime_format),
                 trans.request.host, reset_url)
             frm = trans.app.config.email_from or 'galaxy-no-reply@' + host
             subject = 'Galaxy Password Reset'
             try:
                 util.send_mail(frm, email, subject, body, self.app.config)
                 trans.sa_session.add(reset_user)
                 trans.sa_session.flush()
                 trans.log_event('User reset password: %s' % email)
             except Exception as e:
                 log.debug(body)
                 return "Failed to submit email. Please contact the administrator: %s" % util.unicodify(
                     e)
         else:
             return "Failed to produce password reset token. User not found."
Example #3
0
 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
Example #4
0
 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
Example #5
0
 def create(self, trans: GalaxyWebTransaction, payload: dict, **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
Example #6
0
 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
Example #7
0
 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
Example #8
0
 def reset_password(self, trans, email=None, **kwd):
     """Reset the user's password. Send an email with token that allows a password change."""
     if trans.app.config.smtp_server is None:
         return trans.show_error_message(
             "Mail is not configured for this Galaxy instance "
             "and password reset information cannot be sent. "
             "Please contact your local Galaxy administrator.")
     message = None
     status = 'done'
     if kwd.get('reset_password_button', False):
         message = validate_email(trans, email, check_dup=False)
         if not message:
             # Default to a non-userinfo-leaking response message
             message = (
                 "Your reset request for %s has been received.  "
                 "Please check your email account for more instructions.  "
                 "If you do not receive an email shortly, please contact an administrator."
                 % (escape(email)))
             reset_user = trans.sa_session.query(
                 trans.app.model.User).filter(
                     trans.app.model.User.table.c.email == email).first()
             if not reset_user:
                 # Perform a case-insensitive check only if the user wasn't found
                 reset_user = trans.sa_session.query(
                     trans.app.model.User).filter(
                         func.lower(trans.app.model.User.table.c.email) ==
                         func.lower(email)).first()
             if reset_user:
                 prt = trans.app.model.PasswordResetToken(reset_user)
                 trans.sa_session.add(prt)
                 trans.sa_session.flush()
                 host = trans.request.host.split(':')[0]
                 if host in ['localhost', '127.0.0.1', '0.0.0.0']:
                     host = socket.getfqdn()
                 reset_url = url_for(controller='user',
                                     action="change_password",
                                     token=prt.token,
                                     qualified=True)
                 body = PASSWORD_RESET_TEMPLATE % (
                     host,
                     prt.expiration_time.strftime(
                         trans.app.config.pretty_datetime_format),
                     reset_url)
                 frm = trans.app.config.email_from or 'galaxy-no-reply@' + host
                 subject = 'Galaxy Password Reset'
                 try:
                     util.send_mail(frm, email, subject, body,
                                    trans.app.config)
                     trans.sa_session.add(reset_user)
                     trans.sa_session.flush()
                     trans.log_event("User reset password: %s" % email)
                 except Exception:
                     log.exception('Unable to reset password.')
     return trans.fill_template(
         '/webapps/tool_shed/user/reset_password.mako',
         message=message,
         status=status)
Example #9
0
 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
Example #10
0
    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.'}
Example #11
0
    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 ) )
Example #12
0
    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.'}
Example #13
0
    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))
Example #14
0
    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.'}