Example #1
0
    def sync_user_and_profile(cls, data):
        """Create or update the rero user with the patron data.

        :param data - dict representing the patron data
        """
        # start a session to be able to rollback if the data are not valid
        with db.session.begin_nested():
            user = cls._get_user_by_data(data)
            # need to create the user
            if not user:
                birth_date = data.get('birth_date')
                # sanity check
                if not birth_date:
                    raise RecordValidationError('birth_date field is required')
                # the default password is the birth date
                user = User(email=data.get('email'),
                            password=hash_password(birth_date),
                            profile=dict(),
                            active=True)
                db.session.add(user)
            # update all common fields
            for field in cls.profile_fields:
                # date field need conversion
                if field == 'birth_date':
                    setattr(user.profile, field,
                            datetime.strptime(data.get(field), '%Y-%m-%d'))
                else:
                    setattr(user.profile, field, data.get(field, ''))
            db.session.merge(user)
            if not data.get('user_id'):
                # the fresh created user
                return user
Example #2
0
    def user(self):
        """User account linked to current record.

        :returns: User account.
        """
        email = self.get('email')
        user = datastore.find_user(email=email)

        if not user:
            # Hash password before storing it.
            password = hash_password(email)

            # Create and save new user.
            user = datastore.create_user(email=email, password=password)
            datastore.commit()

            # Send welcome email
            send_welcome_email(self, user)

            # Directly confirm user (no account activation by email)
            confirm_user(user)
        else:
            # If user is not active, activate it.
            if not user.is_active:
                datastore.activate_user(user)

        return user
Example #3
0
    def update(self, data):
        """User record update.

        :param data - dictionary representing a user record to update
        """
        from ..patrons.listener import update_from_profile
        self._validate(data=data)
        email = data.pop('email', None)
        roles = data.pop('roles', None)
        user = self.user
        with db.session.begin_nested():
            if user.profile is None:
                user.profile = UserProfile(user_id=user.id)
            profile = user.profile
            for field in self.profile_fields:
                if field == 'birth_date':
                    setattr(profile, field,
                            datetime.strptime(data.get(field), '%Y-%m-%d'))
                else:
                    setattr(profile, field, data.get(field, ''))
            # change password
            if data.get('password'):
                user.password = hash_password(data['password'])

            if email and email != user.email:
                user.email = email
            # remove the email from user data
            elif not email and user.email:
                user.email = None
            db.session.merge(user)
        db.session.commit()
        confirm_user(user)
        update_from_profile('user', self.user.profile)
        return self
Example #4
0
    def create(cls, data, **kwargs):
        """User record creation.

        :param cls - class object
        :param data - dictionary representing a user record
        """
        with db.session.begin_nested():
            email = data.pop('email', None)
            roles = data.pop('roles', None)
            cls._validate(data=data)
            password = data.pop('password', data.get('birth_date', '123456'))
            user = BaseUser(password=hash_password(password),
                            profile=data,
                            active=True)
            db.session.add(user)
            profile = user.profile
            for field in cls.profile_fields:
                value = data.get(field)
                if value is not None:
                    if field == 'birth_date':
                        value = datetime.strptime(value, '%Y-%m-%d')
                    setattr(profile, field, value)
            # send the reset password notification for new users
            if email:
                user.email = email
            db.session.merge(user)
        db.session.commit()
        if user.email:
            send_reset_password_instructions(user)
        confirm_user(user)
        return cls(user)
Example #5
0
    def _make_user(role_name,
                   organisation='org',
                   organisation_is_shared=True,
                   access=None):
        name = role_name

        if organisation:
            make_organisation(organisation, is_shared=organisation_is_shared)
            name = organisation + name

        email = '{name}@rero.ch'.format(name=name)

        datastore = app.extensions['security'].datastore

        user = datastore.find_user(email=email)

        if user:
            record = UserRecord.get_user_by_email(email)
            return record

        user = datastore.create_user(email=email,
                                     password=hash_password('123456'),
                                     active=True)
        datastore.commit()

        role = datastore.find_role(role_name)
        if not role:
            role = Role(name=role_name)

        role.users.append(user)

        db.session.add(role)

        if access:
            db.session.add(ActionUsers.allow(ActionNeed(access), user=user))

        db.session.commit()

        data = {
            'pid': name,
            'email': email,
            'first_name': name[0].upper() + name[1:],
            'last_name': 'Doe',
            'role': role_name
        }

        if organisation:
            data['organisation'] = {
                '$ref':
                'https://sonar.ch/api/organisations/{organisation}'.format(
                    organisation=organisation)
            }

        record = UserRecord.create(data, dbcommit=True)
        record.reindex()
        db.session.commit()

        return record
Example #6
0
def import_users(infile):
    """Import users."""
    click.secho('Importing users from {file}'.format(file=infile))

    data = json.load(infile)
    for user_data in data:
        try:
            email = user_data.get('email')

            # No email found in user's data, account cannot be created
            if not email:
                raise ClickException('Email not defined')

            user = datastore.find_user(email=email)

            # User already exists, skip account creation
            if user:
                raise ClickException(
                    'User with email {email} already exists'.format(
                        email=email))

            password = user_data.get('password', '123456')
            password = hash_password(password)
            del user_data['password']

            if not user_data.get('roles'):
                user_data['roles'] = [UserRecord.ROLE_USER]

            roles = user_data.get('roles', []).copy()

            for role in roles:
                if not datastore.find_role(role):
                    datastore.create_role(name=role)
                    datastore.commit()

            # Create account and activate it
            datastore.create_user(email=email, password=password, roles=roles)
            datastore.commit()
            user = datastore.find_user(email=email)
            confirm_user(user)
            datastore.commit()

            click.secho(
                'User {email} with ID #{id} created successfully'.format(
                    email=email, id=user.id),
                fg='green')

            # Create user resource
            user = UserRecord.create(user_data, dbcommit=True)
            user.reindex()

        except Exception as error:
            click.secho(
                'User {user} could not be imported: {error}'.format(
                    user=user_data, error=str(error)),
                fg='red')

    click.secho('Finished', fg='green')
Example #7
0
def user_without_role(app, db):
    """Create user in database without role."""
    datastore = app.extensions['security'].datastore
    user = datastore.create_user(email='*****@*****.**',
                                 password=hash_password('123456'),
                                 active=True)
    db.session.commit()

    return user
Example #8
0
def import_users(infile, verbose):
    """Import users."""
    click.secho('Import users:', fg='green')

    data = json.load(infile)
    for patron_data in data:
        email = patron_data.get('email')
        if email is None:
            click.secho('\tUser email not defined!', fg='red')
        else:
            # create User
            password = patron_data.get('password', '123456')
            del(patron_data['password'])
            patron = Patron.get_patron_by_email(email)
            if patron:
                click.secho('\tUser exist: ' + email, fg='yellow')
            else:
                if verbose:
                    click.echo('\tUser: '******'\tUser exist: ' + email, fg='yellow')
                else:
                    pwd = hash_password(password)

                    datastore.create_user(
                        email=email,
                        password=pwd
                    )
                    datastore.commit()
                    user = datastore.find_user(email=email)
                    confirm = confirm_user(user)
                    datastore.commit()
                    if not confirm:
                        click.secho(
                            '\tUser not confirmed!' + email,
                            fg='yellow'
                        )
                    # else:
                    #     click.secho('\tUser confirmed!', fg='green')
                patron = Patron(patron, model=patron.model)
                if patron_data.get('is_patron', False):
                    patron.add_role(role_name='patrons')

                if patron_data.get('is_staff', False):
                    patron.add_role(role_name='staff')
                    # TODO: staff role
                    patron.add_role(role_name='cataloguer')
                patron.reindex()
Example #9
0
    def _make_user(role_name, organisation='org'):
        make_organisation(organisation)

        name = role_name
        if organisation:
            name = organisation + name

        email = '{name}@rero.ch'.format(name=name)

        datastore = app.extensions['security'].datastore

        user = datastore.find_user(email=email)

        if user:
            record = UserRecord.get_user_by_email(email)
            return record

        user = datastore.create_user(email=email,
                                     password=hash_password('123456'),
                                     active=True)
        datastore.commit()

        role = datastore.find_role(role_name)
        if not role:
            role = Role(name=role_name)

        role.users.append(user)

        db.session.add(role)
        db.session.add(
            ActionUsers.allow(ActionNeed(
                '{role}-access'.format(role=role_name)),
                              user=user))
        db.session.commit()

        record = UserRecord.create(
            {
                'pid': name,
                'email': email,
                'full_name': name,
                'roles': [role_name],
                'organisation': {
                    '$ref':
                    'https://sonar.ch/api/organisations/{organisation}'.format(
                        organisation=organisation)
                }
            },
            dbcommit=True)
        record.reindex()
        db.session.commit()

        return record
Example #10
0
    def user(self):
        """Invenio user of a patron."""
        email = self.get('email')
        user = _datastore.find_user(email=email)
        if not user:
            password = hash_password(email)

            _datastore.create_user(email=email, password=password)
            _datastore.commit()
            # send password reset
            user = _datastore.find_user(email=email)
            send_reset_password_instructions(user)
            confirm_user(user)
        return user
Example #11
0
def save_patron(data, record_type, fetcher, minter,
                record_indexer, record_class, parent_pid):
    """Save a record into the db and index it.

    If the user does not exists, it well be created
    and attached to the patron.
    """
    email = data.get('email')
    data = clean_patron_fields(data)
    if email:
        find_user = datastore.find_user(email=email)
        if find_user is None:
            password = hash_password(email)

            datastore.create_user(
                email=email,
                password=password
            )
            datastore.commit()
            # send password reset
            user = datastore.find_user(email=email)
            if user:
                send_reset_password_instructions(user)
                confirm_user(user)

        patron = Patron.get_patron_by_email(email)
        if patron:
            patron = Patron(data, model=patron.model)
            patron.update(data, dbcommit=True, reindex=True)
        else:
            patron = Patron.create(data, dbcommit=True, reindex=True)
        if patron.get('is_patron', False):
            patron.add_role('patrons')
        else:
            patron.remove_role('patrons')

        if patron.get('is_staff', False):
            patron.add_role('staff')
            # TODO: cataloguer role
            patron.add_role('cataloguer')
        else:
            patron.remove_role('cataloguer')
            # TODO: cataloguer role
            patron.remove_role('staff')
        patron.reindex()

    _next = url_for('invenio_records_ui.ptrn', pid_value=patron.pid)
    return _next, patron.persistent_identifier
Example #12
0
def create_user_from_data(data):
    """Create a user and set the profile fields from a data.

    :param data: A dict containing a mix of patron and user data.
    :returns: The modified dict.
    """
    from .modules.users.api import User
    data = deepcopy(data)
    profile_fields = [
        'first_name', 'last_name', 'street', 'postal_code', 'gender', 'city',
        'birth_date', 'username', 'home_phone', 'business_phone',
        'mobile_phone', 'other_phone', 'keep_history', 'country', 'email'
    ]
    user = User.get_by_username(data.get('username'))
    if not user:
        with db.session.begin_nested():
            # create the user
            user = BaseUser(password=hash_password(
                data.get('birth_date', '123456')),
                            profile=dict(),
                            active=True)
            db.session.add(user)
            # set the user fields
            if data.get('email') is not None:
                user.email = data['email']
            profile = user.profile
            # set the profile
            for field in profile_fields:
                value = data.get(field)
                if value is not None:
                    if field == 'birth_date':
                        value = datetime.strptime(value, '%Y-%m-%d')
                    setattr(profile, field, value)
            db.session.merge(user)
        db.session.commit()
        confirm_user(user)
        user_id = user.id
    else:
        user_id = user.user.id
    # remove the user fields from the data
    for field in profile_fields:
        try:
            del data[field]
        except KeyError:
            pass
    data['user_id'] = user_id
    return data
Example #13
0
def user_with_profile(db):
    """Create a simple invenio user with a profile."""
    with db.session.begin_nested():
        user = User(email='*****@*****.**',
                    password=hash_password('123456'),
                    profile=dict(),
                    active=True)
        db.session.add(user)
        profile = user.profile
        profile.birth_date = datetime(1990, 1, 1)
        profile.first_name = 'User'
        profile.last_name = 'With Profile'
        profile.city = 'Nowhere'
        profile.username = '******'
        db.session.merge(user)
    db.session.commit()
    return user
Example #14
0
def import_users(infile, verbose):
    """Import users.

    infile: Json organisation file
    """
    click.secho('Import users:', fg='green')

    data = json.load(infile)
    for patron_data in data:
        email = patron_data.get('email')
        if email is None:
            click.secho('\tUser email not defined!', fg='red')
        else:
            # create User
            password = patron_data.get('password', '123456')
            del(patron_data['password'])
            patron = Patron.get_patron_by_email(email)
            if patron:
                click.secho('\tUser exist: ' + email, fg='yellow')
            else:
                if verbose:
                    click.echo('\tUser: '******'\tUser exist: ' + email, fg='yellow')
                else:
                    pwd = hash_password(password)

                    datastore.create_user(
                        email=email,
                        password=pwd
                    )
                    datastore.commit()
                    user = datastore.find_user(email=email)
                    confirm_user(user)
                    datastore.commit()
                patron = Patron.create(
                    patron_data,
                    dbcommit=True,
                    reindex=True
                )
                patron.reindex()
Example #15
0
def import_users(infile, verbose, password):
    """Import users.

    :param verbose: this function will be verbose.
    :param password: the password to use for user by default.
    :param infile: Json user file.
    """
    click.secho('Import users:', fg='green')

    data = json.load(infile)
    for patron_data in data:
        email = patron_data.get('email')
        if email is None:
            click.secho('\tUser email not defined!', fg='red')
        else:
            # create User
            password = patron_data.get('password', password)
            patron_data.pop('password', None)
            patron = Patron.get_patron_by_email(email)
            if patron:
                click.secho('\tUser exist: ' + email, fg='yellow')
            else:
                if verbose:
                    click.echo('\tUser: '******'\tUser exist: ' + email, fg='yellow')
                else:
                    patron = Patron.create(patron_data,
                                           dbcommit=False,
                                           reindex=False,
                                           email_notification=False)
                    patron.reindex()
                    user = patron.user
                user.password = hash_password(password)
                user.active = True
                db.session.merge(user)
                db.session.commit()
                confirm_user(user)
Example #16
0
def import_users(infile, append, verbose, password, lazy, dont_stop_on_error,
                 debug):
    """Import users.

    :param verbose: this function will be verbose.
    :param password: the password to use for user by default.
    :param lazy: lazy reads file
    :param dont_stop_on_error: don't stop on error
    :param infile: Json user file.
    """
    click.secho('Import users:', fg='green')
    profile_fields = [
        'first_name', 'last_name', 'street', 'postal_code', 'gender', 'city',
        'birth_date', 'username', 'home_phone', 'business_phone',
        'mobile_phone', 'other_phone', 'keep_history', 'country', 'email'
    ]
    if lazy:
        # try to lazy read json file (slower, better memory management)
        data = read_json_record(infile)
    else:
        # load everything in memory (faster, bad memory management)
        data = json.load(infile)
    pids = []
    error_records = []
    for count, patron_data in enumerate(data, 1):
        password = patron_data.get('password', password)
        username = patron_data['username']
        if password:
            patron_data.pop('password', None)
        if verbose:
            user_record = User.get_by_username(username)
            if not user_record:
                click.secho('{count: <8} Creating user: {username}'.format(
                    count=count, username=username))
            else:
                user = user_record.user
                for field in profile_fields:
                    value = patron_data.get(field)
                    if value is not None:
                        if field == 'birth_date':
                            value = datetime.strptime(value, '%Y-%m-%d')
                        setattr(user.profile, field, value)
                db.session.merge(user)
                db.session.commit()
                click.secho('{count: <8} User updated: {username}'.format(
                    count=count, username=username),
                            fg='yellow')
        try:
            # patron creation
            patron = None
            patron_pid = patron_data.get('pid')
            if patron_pid:
                patron = Patron.get_record_by_pid(patron_pid)
            if not patron:
                patron = create_patron_from_data(data=patron_data,
                                                 dbcommit=False,
                                                 reindex=False)
                user = patron.user
                user.password = hash_password(password)
                user.active = True
                db.session.merge(user)
                db.session.commit()
                confirm_user(user)
                patron.reindex()
                pids.append(patron.pid)
            else:
                # remove profile fields from patron record
                for field in profile_fields:
                    patron_data.pop(field, None)
                patron.update(data=patron_data, dbcommit=True, reindex=True)
                if verbose:
                    click.secho(
                        '{count: <8} Patron updated: {username}'.format(
                            count=count, username=username),
                        fg='yellow')
        except Exception as err:
            error_records.append(patron_data)
            click.secho('{count: <8} User create error: {err}'.format(
                count=count, err=err),
                        fg='red')
            if debug:
                traceback.print_exc()
            if not dont_stop_on_error:
                sys.exit(1)
            if debug:
                traceback.print_exc()
            db.session.rollback()

    if append:
        click.secho(f'Append fixtures new identifiers: {len(pids)}')
        identifier = Patron.provider.identifier
        try:
            append_fixtures_new_identifiers(identifier,
                                            sorted(pids, key=lambda x: int(x)),
                                            PatronProvider.pid_type)
        except Exception as err:
            click.secho(f'ERROR append fixtures new identifiers: {err}',
                        fg='red')
    if error_records:
        name, ext = os.path.splitext(infile.name)
        err_file_name = f'{name}_errors{ext}'
        click.secho(f'Write error file: {err_file_name}')
        error_file = JsonWriter(err_file_name)
        for error_record in error_records:
            error_file.write(error_record)
Example #17
0
def import_users(infile, append, verbose, password, lazy, dont_stop_on_error,
                 debug):
    """Import users.

    :param verbose: this function will be verbose.
    :param password: the password to use for user by default.
    :param lazy: lazy reads file
    :param dont_stop_on_error: don't stop on error
    :param infile: Json user file.
    """
    click.secho('Import users:', fg='green')

    if lazy:
        # try to lazy read json file (slower, better memory management)
        data = read_json_record(infile)
    else:
        # load everything in memory (faster, bad memory management)
        data = json.load(infile)
    pids = []
    error_records = []
    for count, patron_data in enumerate(data):
        email = patron_data.get('email')
        password = patron_data.get('password', password)
        username = patron_data['username']
        if email is None:
            click.secho(
                '{count: <8} User {username} do not have email!'.format(
                    count=count, username=username),
                fg='yellow')
        if password:
            patron_data.pop('password', None)
        # do nothing if the patron alredy exists
        patron = Patron.get_patron_by_username(username)
        if patron:
            click.secho('{count: <8} Patron already exist: {username}'.format(
                count=count, username=username),
                        fg='yellow')
            continue

        if verbose:
            click.secho('{count: <8} Creating user: {username}'.format(
                count=count, username=username))
            try:
                profile = UserProfile.get_by_username(username)
                click.secho(
                    '{count: <8} User already exist: {username}'.format(
                        count=count, username=username),
                    fg='yellow')
            except NoResultFound:
                pass
        try:
            # patron creation
            patron = Patron.create(
                patron_data,
                # delete_pid=True,
                dbcommit=False,
                reindex=False,
                email_notification=False)
            user = patron.user
            user.password = hash_password(password)
            user.active = True
            db.session.merge(user)
            db.session.commit()
            confirm_user(user)
            patron.reindex()
            pids.append(patron.pid)
        except Exception as err:
            error_records.append(data)
            click.secho('{count: <8} User create error: {err}'.format(
                count=count, err=err),
                        fg='red')
            if debug:
                traceback.print_exc()
            if not dont_stop_on_error:
                sys.exit(1)
            if debug:
                traceback.print_exc()
            if not dont_stop_on_error:
                sys.exit(1)
    if append:
        click.secho(
            'Append fixtures new identifiers: {len}'.format(len=len(pids)))
        identifier = Patron.provider.identifier
        try:
            append_fixtures_new_identifiers(identifier,
                                            sorted(pids, key=lambda x: int(x)),
                                            PatronProvider.pid_type)
        except Exception as err:
            click.secho(
                "ERROR append fixtures new identifiers: {err}".format(err=err),
                fg='red')
    if error_records:
        name, ext = os.path.splitext(infile.name)
        err_file_name = '{name}_errors{ext}'.format(name=name, ext=ext)
        click.secho('Write error file: {name}'.format(name=err_file_name))
        with open(err_file_name, 'w') as error_file:
            error_file.write('[\n')
            for error_record in error_records:
                for line in json.dumps(error_record, indent=2).split('\n'):
                    error_file.write('  ' + line + '\n')
            error_file.write(']')