예제 #1
0
class Role(CRUDMixin, db.Model):
    """
    TODO:
     - add logic to automatically set `MENU-*` if one `MENU-*-*` is set
     - add logic to automatically remove `MENU-*` if all `MENU-*-*` are removed
    """
    __tablename__ = 'auth_roles'
    name = db.Column(db.String(128), unique=True)
    description = db.Column(db.String(128))
    group = db.Column(db.String(120))
    permissions = db.relationship('Perm',
                                  secondary=role_permission,
                                  backref='roles')

    def __str__(self):
        return f'{self.name}'

    def __repr__(self):
        return f'[Role: {self.name}]'

    def add_permission(self, permission):
        if permission not in self.permissions:
            self.permissions.append(permission)
            self.update()

    def remove_permission(self, permission):
        if permission in self.permissions:
            self.permissions.remove(permission)
            self.update()

    @validates('name')
    def validate_name(self, key, value):
        return value.lower()

    @staticmethod
    def on_changed_name(target, value, oldvalue, initiator):
        target.group = value.split('_')[0]

    def update_users(self, available=[], selected=[]):
        for user in available:
            if user.username in selected and user not in self.users:
                self.users.append(user)
            if user.username not in selected and user in self.users:
                self.users.remove(user)
        self.update()
예제 #2
0
class Perm(CRUDMixin, db.Model):
    __tablename__ = 'auth_permissions'
    name = db.Column(db.String(120), unique=True)
    group = db.Column(db.String(120))

    def __str__(self):
        return f'{self.name}'

    def __repr__(self):
        return f'[Permission: {self.name}]'

    @validates('name')
    def validate_name(self, key, value):
        return value.upper()

    @staticmethod
    def on_changed_name(target, value, oldvalue, initiator):
        target.group = value.split('-')[0]
예제 #3
0
class AuthUserPreference(CRUDMixin, db.Model):
    __tablename__ = 'auth_user_preferences'
    name = db.Column(db.String(64), nullable=False)
    value = db.Column(db.String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('auth_users.id'))
    user = db.relationship('User',
                           foreign_keys=[user_id],
                           backref=db.backref('preferences', lazy='dynamic'))

    def __str__(self):
        return f'{self.name}'

    def __repr__(self):
        return f'[Preference: {self.name}]'

    @validates('name')
    def validate_name(self, key, value):
        return value.upper()

    @validates('value')
    def validate_value(self, key, valoare):
        if not valoare:
            return None
        return valoare
예제 #4
0
class User(CRUDMixin, UserMixin, db.Model):
    __tablename__ = 'auth_users'
    email = db.Column(db.String(64), unique=True, index=True)
    name = db.Column(db.String(64))
    locale = db.Column(db.String(5), default='en')
    location = db.Column(db.String(64))
    username = db.Column(db.String(32), nullable=False, unique=True)
    birthdate = db.Column(db.Date)

    password_hash = db.Column(db.String(256), nullable=False)
    token = db.Column(db.String(256), index=True, unique=True)
    active = db.Column(db.Boolean, default=True, nullable=False)
    force_pwd_change = db.Column(db.Boolean, nullable=False, default=False)
    confirmed = db.Column(db.Boolean, default=False)
    failed_attempts = db.Column(db.Integer, nullable=False, default=0)

    type = db.Column(db.String(20))
    __mapper_args__ = {
        'polymorphic_on': type,
        'polymorphic_identity': 'user',
    }

    _roles = db.relationship(
        'Role',
        secondary=user_role,
        backref=db.backref('users', lazy='dynamic'),
    )
    roles = association_proxy('_roles', 'name')

    def __str__(self):
        return f'{self.name}'

    def __repr__(self):
        return f'{self.type}: {self.name}'

    @validates('location')
    def validate_location(self, key, value):
        if not value:
            return None
        return value

    @property
    def password(self):
        raise AttributeError('´password´ is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)
        self.token = None  # if user is changing passwords, also revoke token

    def verify_password(self, password):
        result = check_password_hash(self.password_hash, password)
        if not result:
            self.failed_attempts += 1
        else:
            self.failed_attempts = 0
        self.update()
        return result

    @property
    def permissions(self):
        permissions = []
        names = []
        for role in self._roles:
            permissions += role.permissions
        for permission in permissions:
            names.append(permission.name)
        return names

    def has_permission(self, permission):
        if self.is_admin or permission.upper() in self.permissions:
            return True
        return False

    def hp(self, permission):
        return self.has_permission(permission)

    def has_role(self, role):
        if self.is_admin:
            return True
        if role in self.roles:
            return True
        return False

    def add_role(self, role):
        if role not in self._roles:
            self._roles.append(role)
            self.update()

    def update_roles(self, available_roles=[], selected_roles=[]):
        for role in available_roles:
            if role.name in selected_roles and role not in self._roles:
                self._roles.append(role)
            if role.name not in selected_roles and role in self._roles:
                self._roles.remove(role)
        self.update()

    def remove_role(self, role):
        if role in self._roles:
            self._roles.remove(role)
            self.update()

    @property
    def _is_ddic(self):
        if self.is_admin:
            return True
        return False

    @property
    def is_admin(self):
        if self.email in current_app.config['RUNE_ADMINS']:
            return True
        return False

    def to_dict(self):
        """Export user to a dictionary."""
        return {
            'id':
            self.id,
            'username':
            self.username,
            'name':
            self.name,
            'email':
            self.email,
            'active':
            self.active,
            'is_admin':
            self.is_admin,
            'force_pwd_change':
            self.force_pwd_change,
            'type':
            self.type,
            'failed_attempts':
            self.failed_attempts,
            'roles': [role for role in self.roles],
            'permissions':
            self.permissions,
            'links': [
                {
                    'url': url_for('api.auth_user_details',
                                   username=self.username),
                    'text': 'Details'
                },
                {
                    'url': url_for('api.auth_user_delete',
                                   username=self.username),
                    'text': 'Delete'
                },
            ]
        }

    def from_dict(self, data, new_user=False):
        allowed_fields = [
            'username',
            'email',
            'name',
            'birthdate',
            'locale',
            'location',
        ]

        for field in allowed_fields:
            if field in data:
                setattr(self, field, data[field])

        if new_user and 'password' in data:
            self.set_password(data['password'])

    @staticmethod
    def on_changed_email(target, value, oldvalue, initiator):
        """Update the `username` when the email changes."""
        target.username = value.split('@')[0]

    @staticmethod
    def on_changed_failed_attempts(target, value, oldvalue, initiator):
        """Deactivate user if the failed attempts limit is reached."""
        if target.failed_attempts >= 5:
            target.active = False
예제 #5
0
class Notification(CRUDMixin, db.Model):
    __tablename__ = 'main_messages'
    locale = db.Column(db.String(5), default='en')
    body = db.Column(db.Text)
    body_html = db.Column(db.Text)
    author_id = db.Column(db.Integer, db.ForeignKey('auth_users.id'))
    author = db.relationship('User',
                             foreign_keys=[author_id],
                             backref=db.backref('messages', lazy='dynamic'))
    start_date = db.Column(db.Date, nullable=False, default=date.today())
    end_date = db.Column(db.Date, nullable=False, default=date.today())

    @property
    def visible(self):
        return self.start_date <= date.today() <= self.end_date

    @property
    def expired(self):
        return self.end_date < date.today()

    @staticmethod
    def read():
        messages = Notification.query.filter(
            and_(Notification.start_date <= date.today(),
                 Notification.end_date >= date.today(),
                 Notification.locale == g.locale)).all()
        return messages

    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        target.body_html = linkify(
            clean(markdown(value,
                           output_format='html',
                           extensions=mkd.allowed_extensions),
                  tags=mkd.allowed_tags,
                  attributes=mkd.allowed_attrs,
                  strip=True))

    def to_json(self):
        return {
            'id': self.id,
            'body': self.body_html,
            'author_id': self.author_id,
            'locale': self.locale,
            'start_date': self.start_date,
            'end_date': self.end_date,
        }

    def from_json(self, data):
        allowed_fields = [
            'locale',
            'body',
            'author_id',
        ]

        date_fields = [
            'start_date',
            'end_date',
        ]

        for field in allowed_fields:
            print(data[field])
            try:
                setattr(self, field, data[field])
            except KeyError:
                pass

        for field in date_fields:
            try:
                setattr(self, field, parse(data[field]))
            except KeyError:
                pass