Esempio n. 1
0
class Category(db.Model):
    __tablename__ = 'categories'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50), unique=True)
    posts = db.relationship('Post', backref="category", lazy="dynamic")

    def __init__(self, **kwargs):
        super(Category, self).__init__(**kwargs)
        if self.name is None:
            self.name = "Other"

    @staticmethod
    def insert_categories():
        categories = [
            "Netsec", "Linux", "Python", "Algorithms", "Math",
            "Data Engineering", "Electronics", "C", "MicroPython", "IoT",
            "Webdevelopment"
        ]
        for c in categories:
            cat = Category.query.filter_by(name=c).first()
            if cat is None:
                cat = Category(name=c)
            db.session.add(cat)
        db.session.commit()

    def __repr__(self):
        return "Category : {}".format(self.name)
Esempio n. 2
0
class Tag(db.Model):
    """ORM class used for modelling tags.

    Inherit for SQLAlchemy.Model.
    Create class variables which the ORM uses as table columns.

    ---

    Class variables
    ---------------
    id : SQLALchemy.Column
        integer, primary key
    content: SQLALchemy.Column
        string, mandatory
    post_id: SQLALchemy.Column
        integer, foreign key, points to Post.id

    Methods
    -------
    __repr__(self): str
        string representation of a Tag
    """

    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(20), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)

    def __repr__(self):
        return f"Tag {self.id} for post {self.post_id}\n"
Esempio n. 3
0
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __init__(self, **kwargs):
        super(Role, self).__init__(**kwargs)
        if self.permissions is None:
            self.permissions = 0

    @staticmethod
    def insert_roles():
        roles = {
            'User': [Permission.COMMENT],
            'Writer': [Permission.COMMENT, Permission.WRITE],
            'Moderator':
            [Permission.COMMENT, Permission.WRITE, Permission.MODERATE],
            'Administrator': [
                Permission.COMMENT, Permission.WRITE, Permission.MODERATE,
                Permission.ADMIN
            ]
        }
        default_role = 'User'
        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            role.reset_permissions()
            for perm in roles[r]:
                role.add_permission(perm)
            role.default = (role.name == default_role)
            db.session.add(role)
        db.session.commit()

    def add_permission(self, perm):
        if not self.has_permission(perm):
            self.permissions += perm

    def remove_permission(self, perm):
        if self.has_permission(perm):
            self.permissions -= perm

    def reset_permissions(self):
        self.permissions = 0

    def has_permission(self, perm):
        return self.permissions & perm == perm

    def __repr__(self):
        return "Role {}".format(self.name)
Esempio n. 4
0
class Post(SearchableMixin, db.Model):
    """ORM class used for modelling posts and their behavior.

    Inherit for SQLAlchemy.Model and SearchableMixin.
    Create class variables which the ORM uses as table columns.

    ---

    Class variables
    ---------------
    __searchable__ : list[str]
        names of columns which should be full-text searched
    id : SQLALchemy.Column
        integer, primary key
    title: SQLALchemy.Column
        string, mandatory, indexed
    date_posted: SQLALchemy.Column
        datetime, mandatory, indexed, defaults to utcnow
    content: SQLALchemy.Column
        text, mandatory
    user_id: SQLALchemy.Column
        integer, foreign key, points to User.id
    tags: SQLAlchemy.relationship
        every tag record has a parent post, delete on cascade
    comments: SQLAlchemy.relationship
        every comment record has a parent post, delete on cascade

    Methods
    -------
    __repr__(self): str
        string representation of a Post instance
    """

    __searchable__ = ['content']
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), index=True, nullable=False)
    date_posted = db.Column(db.DateTime, nullable=False, index=True,
                            default=datetime.utcnow)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    # 'user' above is in lowercase because it references the table name
    comments = db.relationship('Comment', cascade='all,delete',
                               backref='parent_post', lazy=True)
    tags = db.relationship('Tag', cascade='all,delete', backref='parent_post',
                           lazy=True)

    def __repr__(self):
        return f"Blog post: {self.title}, \nPosted on: {self.date_posted}\n"
Esempio n. 5
0
class Comment(db.Model):
    """ORM class used for modelling comments.

    Inherit for SQLAlchemy.Model.
    Create class variables which the ORM uses as table columns.

    ---

    Class variables
    ---------------
    id : SQLALchemy.Column
        integer, primary key
    date_posted: SQLALchemy.Column
        datetime, mandatory, indexed, defaults to utcnow
    content: SQLALchemy.Column
        text, mandatory
    user_id: SQLALchemy.Column
        integer, foreign key, points to User.id
    post_id: SQLALchemy.Column
        integer, foreign key, points to Post.id

    Methods
    -------
    __repr__(self): str
        string representation of a Comment
    """

    id = db.Column(db.Integer, primary_key=True)
    date_posted = db.Column(db.DateTime, nullable=False, index=True,
                            default=datetime.utcnow)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)

    def __repr__(self):
        return f"Comment {self.id} by user {self.user_id} for "\
                f"post {self.post_id}\n"
Esempio n. 6
0
class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), unique=True, nullable=False)
    body = db.Column(db.Text, nullable=False)
    body_html = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    category_id = db.Column(db.Integer, db.ForeignKey("categories.id"))
    comments = db.relationship('Comment', backref='post', lazy='dynamic')

    def __repr__(self):
        return "Category : {}, Title {}".format(self.category_id, self.title)

    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        md = Markdown(renderer=HighLightRenderer(), extensions=['fenced-code'])
        target.body_html = md(value)
Esempio n. 7
0
class Comment(db.Model):
    __tablename__ = 'comments'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    body_html = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    disabled = db.Column(db.Boolean)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))

    @staticmethod
    def on_changed_body(target, value, oldvalue, initiator):
        allowed_tags = [
            'a', 'abbr', 'acronym', 'b', 'code', 'em', 'i', 'strong'
        ]
        target.body_html = bleach.linkify(
            bleach.clean(markdown(value,
                                  output_format='html',
                                  extensions=["fenced_code"]),
                         tags=allowed_tags,
                         strip=True))
Esempio n. 8
0
class Book(db.Model):
    """ORM class used for modelling books.

    Inherit for SQLAlchemy.Model.
    Create class variables which the ORM uses as table columns.

    ---

    Class variables
    ---------------
    id : SQLALchemy.Column
        integer, primary key
    title: SQLALchemy.Column
        string, mandatory, indexed
    authors: SQLALchemy.Column
        string, mandatory
    edition: SQLAlchemy.Column
        string, mandatory
    link: SQLAlchemy.Column
        string
    description: SQLAlchemy.Column
        text, mandatory

    Methods
    -------
    __repr__(self): str
        string representation of a Book
    """

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(60), nullable=False, index=True)
    authors = db.Column(db.String(60), nullable=False)
    edition = db.Column(db.String(20), nullable=False)
    link = db.Column(db.String(60))
    description = db.Column(db.Text, nullable=False)

    def __repr__(self):
        return f"Book {self.id} titled {self.title}\n"
Esempio n. 9
0
class User(db.Model, UserMixin):
    """ORM class used for modelling users and their behavior.

    Inherit for SQLAlchemy.Model and login_manager.UserMixin.
    Create class variables which the ORM uses as table columns.

    ---

    Class variables
    ---------------
    id : SQLALchemy.Column
        integer, primary key
    username: SQLALchemy.Column
        string, unique, mandatory, indexed
    profile_pic: SQLALchemy.Column
        filepath string, mandatory, defaults to default.png
    password: SQLALchemy.Column
        hashed string, mandatory
    is_admin: SQLALchemy.Column
        boolean, defaults to False, only 1 user can have it set to True
    posts: SQLAlchemy.relationship
        every post record has a user author, delete on cascade
    comments: SQLAlchemy.relationship
        every comment record has a user author, delete on cascade

    Methods
    -------
    __repr__(self): str
        string representation of a User instance
    get_reset_token(self, expiration_secs): str
        get a password reset token for the user
    verify_reset_token(token): User instance or None
        get back the user if with that password reset token
    """

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, index=True,
                         nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    profile_pic = db.Column(db.String(20), nullable=False,
                            default='default.png')
    password = db.Column(db.String(60), nullable=False)
    is_admin = db.Column(db.Boolean, default=False)
    posts = db.relationship('Post', backref='author', cascade='all, delete',
                            lazy=True)
    # 'Post' in uppercase because it references the class name
    comments = db.relationship('Comment', backref='author',
                               cascade='all,delete', lazy=True)

    def __repr__(self):
        return f"User: {self.username}, \nEmail: {self.email}\n"

    def get_reset_token(self, expiration_secs=600):
        """Get a password reset token.

        ---

        Parameters
        ----------
        expiration_secs: int
            seconds after which the token expires, defaults to 600

        Returns
        -------
        the reset token: str
            the token received from the serializer and decoded to str
        """

        serializer = Serializer(current_app.config['SECRET_KEY'],
                                expiration_secs)
        return serializer.dumps({'user_id': self.id}).decode('utf-8')

    @staticmethod
    def verify_reset_token(token):
        """Static method, verify password reset token.

        ---

        Parameters
        ----------
        token: str
            the password reset token to be verified

        Returns
        -------
        the verified user: User instance
            the user queried by the user_id on the token load
        """

        serializer = Serializer(current_app.config['SECRET_KEY'])
        user_id = serializer.loads(token)['user_id']
        return User.query.get(user_id)
Esempio n. 10
0
class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    password_hash = db.Column(db.String(128))
    confirmed = db.Column(db.Boolean, default=False)
    image_file = db.Column(db.String(20),
                           nullable=False,
                           default='default.jpg')
    name = db.Column(db.String(64))
    location = db.Column(db.String(64))
    about_me = db.Column(db.Text())
    member_since = db.Column(db.DateTime(), default=datetime.utcnow)
    last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    comments = db.relationship('Comment', backref='author', lazy='dynamic')

    def __init__(self, **kwargs):
        super(User, self).__init__(**kwargs)
        if self.role is None:
            if self.email == current_app.config['ADMIN']:
                self.role = Role.query.filter_by(name='Administrator').first()
            if self.role is None:
                self.role = Role.query.filter_by(default=True).first()

    def __repr__(self):
        return 'User {}'.format(self.username)

    @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)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def generate_confirmation_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'confirm': self.id}).decode('utf-8')

    def confirm(self, token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token.encode('utf-8'))
        except:
            return False
        if data.get('confirm') != self.id:
            return False
        self.confirmed = True
        db.session.add(self)
        return True

    def generate_reset_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'reset': self.id}).decode('utf-8')

    @staticmethod
    def reset_password(token, new_password):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token.encode('utf-8'))
        except:
            return False
        user = User.query.get(data.get('reset'))
        if user is None:
            return False
        user.password = new_password
        db.session.add(user)
        return True

    def generate_email_change_token(self, new_email, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({
            'change_email': self.id,
            'new_email': new_email
        }).decode('utf-8')

    def change_email(self, token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token.encode('utf-8'))
        except:
            return False
        if data.get('change_email') != self.id:
            return False
        new_email = data.get('new_email')
        if new_email is None:
            return False
        if self.query.filter_by(email=new_email).first() is not None:
            return False
        self.email = new_email
        db.session.add(self)
        return True

    def can(self, perm):
        return self.role is not None and self.role.has_permission(perm)

    def ping(self):
        self.last_seen = datetime.utcnow()
        db.session.add(self)

    def is_administrator(self):
        return self.can(Permission.ADMIN)