def create_or_update( self, username, password, email, firstname='', lastname='', active=True, admin=False, extern_type=None, extern_name=None, cur_user=None, plugin=None, force_password_change=False, allow_to_create_user=True, create_repo_group=False, updating_user_id=None, language=None, strict_creation_check=True): """ Creates a new instance if not found, or updates current one :param username: :param password: :param email: :param firstname: :param lastname: :param active: :param admin: :param extern_type: :param extern_name: :param cur_user: :param plugin: optional plugin this method was called from :param force_password_change: toggles new or existing user flag for password change :param allow_to_create_user: Defines if the method can actually create new users :param create_repo_group: Defines if the method should also create an repo group with user name, and owner :param updating_user_id: if we set it up this is the user we want to update this allows to editing username. :param language: language of user from interface. :returns: new User object with injected `is_new_user` attribute. """ if not cur_user: cur_user = getattr(get_current_rhodecode_user(), 'username', None) from rhodecode.lib.auth import ( get_crypt_password, check_password, generate_auth_token) from rhodecode.lib.hooks_base import ( log_create_user, check_allowed_create_user) def _password_change(new_user, password): # empty password if not new_user.password: return False # password check is only needed for RhodeCode internal auth calls # in case it's a plugin we don't care if not plugin: # first check if we gave crypted password back, and if it matches # it's not password change if new_user.password == password: return False password_match = check_password(password, new_user.password) if not password_match: return True return False user_data = { 'username': username, 'password': password, 'email': email, 'firstname': firstname, 'lastname': lastname, 'active': active, 'admin': admin } if updating_user_id: log.debug('Checking for existing account in RhodeCode ' 'database with user_id `%s` ' % (updating_user_id,)) user = User.get(updating_user_id) else: log.debug('Checking for existing account in RhodeCode ' 'database with username `%s` ' % (username,)) user = User.get_by_username(username, case_insensitive=True) if user is None: # we check internal flag if this method is actually allowed to # create new user if not allow_to_create_user: msg = ('Method wants to create new user, but it is not ' 'allowed to do so') log.warning(msg) raise NotAllowedToCreateUserError(msg) log.debug('Creating new user %s', username) # only if we create user that is active new_active_user = active if new_active_user and strict_creation_check: # raises UserCreationError if it's not allowed for any reason to # create new active user, this also executes pre-create hooks check_allowed_create_user(user_data, cur_user, strict_check=True) self.send_event(UserPreCreate(user_data)) new_user = User() edit = False else: log.debug('updating user %s', username) self.send_event(UserPreUpdate(user, user_data)) new_user = user edit = True # we're not allowed to edit default user if user.username == User.DEFAULT_USER: raise DefaultUserException( _("You can't edit this user (`%(username)s`) since it's " "crucial for entire application") % {'username': user.username}) # inject special attribute that will tell us if User is new or old new_user.is_new_user = not edit # for users that didn's specify auth type, we use RhodeCode built in from rhodecode.authentication.plugins import auth_rhodecode extern_name = extern_name or auth_rhodecode.RhodeCodeAuthPlugin.name extern_type = extern_type or auth_rhodecode.RhodeCodeAuthPlugin.name try: new_user.username = username new_user.admin = admin new_user.email = email new_user.active = active new_user.extern_name = safe_unicode(extern_name) new_user.extern_type = safe_unicode(extern_type) new_user.name = firstname new_user.lastname = lastname if not edit: new_user.api_key = generate_auth_token(username) # set password only if creating an user or password is changed if not edit or _password_change(new_user, password): reason = 'new password' if edit else 'new user' log.debug('Updating password reason=>%s', reason) new_user.password = get_crypt_password(password) if password else None if force_password_change: new_user.update_userdata(force_password_change=True) if language: new_user.update_userdata(language=language) self.sa.add(new_user) if not edit and create_repo_group: # create new group same as username, and make this user an owner desc = RepoGroupModel.PERSONAL_GROUP_DESC % {'username': username} RepoGroupModel().create(group_name=username, group_description=desc, owner=username, commit_early=False) if not edit: # add the RSS token AuthTokenModel().create(username, description='Generated feed token', role=AuthTokenModel.cls.ROLE_FEED) log_create_user(created_by=cur_user, **new_user.get_dict()) return new_user except (DatabaseError,): log.error(traceback.format_exc()) raise