Example #1
0
def test_to_struct():
    s = utils.to_struct(n="Hello", b="Bye")
    assert s.n == "Hello"
Example #2
0
def model(UserModel):
    """
    Post Model
    :param UserModel:
    """

    db = UserModel.db

    class SlugNameMixin(object):
        name = db.Column(db.String(255), index=True)
        slug = db.Column(db.String(255), index=True, unique=True)
        description = db.Column(db.String(255))
        image_url = db.Column(db.Text)

        @classmethod
        def get_by_slug(cls, slug=None, name=None):
            """
            Return a post by slug
            """
            if name and not slug:
                slug = utils.slugify(name)
            return cls.all().filter(cls.slug == slug).first()

        @classmethod
        def new(cls, name, slug=None):
            slug = utils.slugify(name if not slug else slug)
            return cls.create(name=name, slug=slug)

        def rename(self, name, slug=None):
            slug = utils.slugify(name if not slug else slug)
            return self.update(name=name, slug=slug)

    class PublisherType(SlugNameMixin, db.Model):
        """
        Types
        """
        @property
        def total_posts(self):
            return PublisherPost.all().filter(PublisherPost.type_id == self.id).count()

    class PublisherCategory(SlugNameMixin, db.Model):
        """
        Category
        """
        @property
        def total_posts(self):
            return PublisherCategoryMap.all()\
                .filter(PublisherCategoryMap.category_id == self.id)\
                .count()

    class PublisherTag(SlugNameMixin, db.Model):
        """
        Tag
        """
        @property
        def total_posts(self):
            return PublisherTagMap.all()\
                .filter(PublisherTagMap.tag_id == self.id)\
                .count()

    class PublisherTagMap(db.Model):
        """
        PostPostTag
        """
        post_id = db.Column(db.Integer, db.ForeignKey("publisher_post.id", ondelete='CASCADE'))
        tag_id = db.Column(db.Integer, db.ForeignKey(PublisherTag.id, ondelete='CASCADE'))

        @classmethod
        def add(cls, post_id, tag_id):
            c = cls.all().filter(cls.post_id == post_id)\
                .filter(cls.tag_id == tag_id)\
                .first()
            if not c:
                cls.create(post_id=post_id, tag_id=tag_id)

        @classmethod
        def remove(cls, post_id, tag_id):
            c = cls.all().filter(cls.post_id == post_id)\
                .filter(cls.tag_id == tag_id)\
                .first()
            if c:
                c.delete(hard_delete=True)

    class PublisherCategoryMap(db.Model):
        post_id = db.Column(db.Integer, db.ForeignKey("publisher_post.id", ondelete='CASCADE'))
        category_id = db.Column(db.Integer, db.ForeignKey(PublisherCategory.id, ondelete='CASCADE'))

        @classmethod
        def add(cls, post_id, category_id):
            c = cls.all().filter(cls.post_id == post_id)\
                .filter(cls.category_id == category_id)\
                .first()
            if not c:
                cls.create(post_id=post_id, category_id=category_id)

        @classmethod
        def remove(cls, post_id, category_id):
            c = cls.all().filter(cls.post_id == post_id)\
                .filter(cls.category_id == category_id)\
                .first()
            if c:
                c.delete(hard_delete=True)

    class PublisherPost(db.Model):

        user_id = db.Column(db.Integer, db.ForeignKey(UserModel.id))
        type_id = db.Column(db.Integer, db.ForeignKey(PublisherType.id))

        title = db.Column(db.String(255))
        slug = db.Column(db.String(255), index=True)
        content = db.Column(db.Text)
        description = db.Column(db.Text)
        featured_image = db.Column(db.Text)
        featured_embed = db.Column(db.Text)
        featured_media_top = db.Column(db.String(10))
        language = db.Column(db.String(255))
        parent_id = db.Column(db.Integer)  # If the post is derived from another post
        is_child = db.Column(db.Boolean, index=True, default=False)  #
        is_list = db.Column(db.Boolean, index=True, default=False)  # A list is a type of post having sub post
        is_featured = db.Column(db.Boolean, index=True, default=False)  # Feature post are limited
        featured_at = db.Column(db.DateTime)
        is_sticky = db.Column(db.Boolean, index=True, default=False)  # A sticky post usually stay on top, no matter the count
        sticky_at = db.Column(db.DateTime)
        is_published = db.Column(db.Boolean, index=True, default=True)
        published_at = db.Column(db.DateTime)
        published_by = db.Column(db.Integer)
        is_revision = db.Column(db.Boolean, default=False)
        revision_id = db.Column(db.Integer)  # When updating the post, will auto-save

        is_public = db.Column(db.Boolean, index=True, default=False)
        is_draft = db.Column(db.Boolean, index=True, default=False)
        options_data = db.Column(db.Text, default="{}")
        menu_order = db.Column(db.Integer, default=0, index=True)

        author = db.relationship(UserModel, backref="posts")
        type = db.relationship(PublisherType, backref="posts")
        categories = db.relationship(PublisherCategory,
                                     secondary=PublisherCategoryMap.__table__.name)
        tags = db.relationship(PublisherTag,
                                     secondary=PublisherTagMap.__table__.name)

        @classmethod
        def new(cls, title, **kwargs):
            """
            Insert a new post
            """
            published_date = None
            is_revision = False
            is_published = False
            is_draft = False
            is_public = kwargs.get("is_public", True)
            parent_id = kwargs.get("parent_id", None)

            if kwargs.get("is_revision"):
                if not parent_id:
                    raise ModelError("'parent_id' is missing for revision")
                is_revision = True
                is_public = False
            elif kwargs.get("is_draft"):
                is_draft = True
                is_public = False
            elif kwargs.get("is_published"):
                is_published = True
                published_date = datetime.datetime.now()

            slug = None
            if is_published or is_draft:
                slug = cls.create_slug(kwargs.get("slug", title))

            type_id = kwargs.get("type_id")
            if not type_id and kwargs.get("type_slug"):
                type_slug = kwargs.get("type_slug")
                _type = PublisherType.get_by_slug(slug=type_slug)
                if _type:
                    type_id = _type.id

            data = {
                "user_id": kwargs.get("user_id", 0),
                "title": title,
                "slug": slug,
                "content": kwargs.get("content"),
                "description": kwargs.get("description"),
                "is_published": is_published,
                "published_at": published_date,
                "is_draft": is_draft,
                "is_revision": is_revision,
                "is_public": is_public,
                "parent_id": parent_id,
                "type_id": type_id
            }
            return cls.create(**data)

        @classmethod
        def get_published(cls, id=None, slug=None, types=[], categories=[], tags=[]):
            """
            Return published posts.
            If $id or $slug it will return a single post, else all

            :param id: int - the id of a post
            :param slug: string - the slug of a post
            :param types: list - list of types slugs
            :param categories: list - list of categories slug
            :param tags: list - list of tags slugs
            :return:
            """
            q = cls.all().filter(cls.is_published == True)

            # Query only a single post
            if id or slug:
                if id:
                    q = q.filter(cls.id == id)
                elif slug:
                    q = q.filter(cls.slug == slug)
                return q.first()

            # Query lists
            else:
                if types:
                    q = q.join(PublisherType)\
                        .filter(PublisherType.slug.in_(types))
                if categories:
                    q = q.join(PublisherCategoryMap)\
                        .join(PublisherCategory)\
                        .filter(PublisherCategory.slug.in_(categories))
                if tags:
                    q = q.join(PublisherTag)\
                        .filter(PublisherTag.slug.in_(tags))
                return q

        @classmethod
        def create_slug(cls, title):
            slug = None
            slug_counter = 0
            _slug = utils.slugify(title).lower()
            while True:
                slug = _slug
                if slug_counter > 0:
                    slug += str(slug_counter)
                slug_counter += 1
                if not cls.get_by_slug(slug):
                    break
            return slug

        @classmethod
        def get_by_slug(cls, slug):
            """
            Return a post by slug
            """
            return cls.all().filter(cls.slug == slug).first()

        def publish(self, published_date=None, published_by_id=None):
            if self.is_draft:
                data = {
                    "is_draft": False,
                    "is_published": True,
                    "published_at": published_date or datetime.datetime.now()
                }
                if published_by_id:
                    data.update({
                        "published_by": published_by_id
                    })

                self.update(**data)

        def set_slug(self, title):
            slug = utils.slugify(title)
            if title and slug != self.slug:
                slug = self.create_slug(slug)
                self.update(slug=slug)

        def update_categories(self, categories_list):
            """
            Update categories by replacing existing list with new list
            :param categories_list: list. The new list of category
            """
            cats = PublisherCategoryMap.all()\
                    .filter(PublisherCategoryMap.post_id == self.id)
            cats_list = [c.category_id for c in cats]

            del_cats = list(set(cats_list) - set(categories_list))
            new_cats = list(set(categories_list) - set(cats_list))

            for dc in del_cats:
                PublisherCategoryMap.remove(post_id=self.id, category_id=dc)

            for nc in new_cats:
                PublisherCategoryMap.add(post_id=self.id, category_id=nc)

        def update_tags(self, tags_list):
            """
            Update tags by replacing existing list with new list
            :param tags_list: list. The new list of tags
            """
            tags = PublisherTagMap.all()\
                    .filter(PublisherTagMap.post_id == self.id)
            tags_list_ = [c.tag_id for c in tags]

            del_tags = list(set(tags_list_) - set(tags_list))
            new_tags = list(set(tags_list) - set(tags_list_))

            for dc in del_tags:
                PublisherTagMap.remove(post_id=self.id, tag_id=dc)

            for nc in new_tags:
                PublisherTagMap.add(post_id=self.id, tag_id=nc)

        def get_list(self):
            if not self.is_list:
                return None

            return PublisherPost.all()\
                .filter(PublisherPost.is_published == True)\
                .filter(PublisherPost.is_child == True)\
                .filter(PublisherPost.parent_id == self.id)

        def delete_revisions(self):
            """
            Delete all revisions
            """
            try:
                PublisherPost.all()\
                    .filter(PublisherPost.post_id == self.id)\
                    .filter(PublisherPost.is_revision == True)\
                    .delete()
                PublisherPost.db.commit()
            except Exception as ex:
                PublisherPost.db.rollback()

        def set_options(self, key, values):
            options = self.options
            options.update({key: values})
            self.update(options_data=json.dumps(options))

        @property
        def options(self):
            return json.loads(self.options_data) if self.options_data else {}

        @property
        def excerpt(self):
            """
            Return description as excerpt, if empty,
            it will return the first paragraph
            :return: str
            """
            if self.description:
                return self.description
            else:
                return ""

        @property
        def top_image(self):
            """
            Return the top image
            Return the image url if exists, or it will get the first image
            Will get the first image from the markdown
            """
            if self.featured_image:
                return self.featured_image
            elif self.content:
                md_images = markdown_ext.extract_images(self.content)
                return md_images[0] if md_images else None

        @property
        def status(self):
            if self.is_published:
                return "Published"
            elif self.is_draft:
                return "Draft"
            elif self.is_revision:
                return "Revision"
            else:
                return ""

        @property
        def total_revisions(self):
            return PublisherPost.all()\
                .filter(PublisherPost.post_id == self.id)\
                .filter(PublisherPost.is_revision == True)\
                .count()

    class PublisherUploadObject(db.Model):
        parent_id = db.Column(db.Integer, index=True)
        user_id = db.Column(db.Integer, index=True)
        provider = db.Column(db.String(255))
        container = db.Column(db.String(255))
        local_path = db.Column(db.Text)
        name = db.Column(db.Text)
        description = db.Column(db.String(255))
        size = db.Column(db.Integer)
        extension = db.Column(db.String(10), index=True)
        type = db.Column(db.String(25), index=True)
        object_path = db.Column(db.Text)
        object_url = db.Column(db.Text)
        is_private = db.Column(db.Boolean, index=True, default=False)

    return utils.to_struct(Post=PublisherPost,
                           Category=PublisherCategory,
                           Type=PublisherType,
                           CategoryMap=PublisherCategoryMap,
                           Tag=PublisherTag,
                           TagMap=PublisherTagMap,
                           UploadObject=PublisherUploadObject)
Example #3
0
def model(db):
    class UserRole(db.Model):

        name = db.Column(db.String(75), index=True)
        level = db.Column(db.Integer, index=True)

        @classmethod
        def new(cls, name, level):
            name = utils.slugify(name)
            role = cls.get_by_name(name)
            if not role:
                role = cls.create(name=name, level=level)
            return role

        @classmethod
        def get_by_name(cls, name):
            name = utils.slugify(name)
            return cls.all().filter(cls.name == name).first()

        @classmethod
        def get_by_level(cls, level):
            return cls.all().filter(cls.level == level).first()

    class User(db.Model, UserMixin):

        role_id = db.Column(db.Integer, db.ForeignKey(UserRole.id))
        email = db.Column(db.String(75), index=True, unique=True)
        email_confirmed = db.Column(db.Boolean, default=False)
        password_hash = db.Column(db.String(255))
        has_temp_login = db.Column(db.Boolean, default=False)
        temp_login_token = db.Column(db.String(100), index=True)
        temp_login_expiration = db.Column(db.DateTime)
        first_name = db.Column(db.String(255))
        last_name = db.Column(db.String(255))
        date_of_birth = db.Column(db.Date)
        sex = db.Column(
            db.String(10)
        )  # To get confusion out of the way, Sex refers to natural/biological features.
        profile_image_url = db.Column(db.String(255))
        signup_method = db.Column(db.String(255))
        active = db.Column(db.Boolean, default=True, index=True)
        last_login = db.Column(db.DateTime)
        last_visited = db.Column(db.DateTime)
        role = db.relationship(UserRole)

        # ------ FLASK-LOGIN REQUIRED METHODS ----------------------------------

        @property
        def is_active(self):
            return self.active

        # ---------- END FLASK-LOGIN REQUIREMENTS ------------------------------

        @classmethod
        def get_by_email(cls, email):
            """
            Return a User by email address
            """
            return cls.all().filter(cls.email == email).first()

        @classmethod
        def get_by_temp_login(cls, token):
            """
            Return a User by temp_login_token
            temp_login_token allows a user to login with the token
            and reset the password
            """
            user = cls.all().filter(cls.temp_login_token == token).first()
            if user:
                now = datetime.datetime.now()
                if user.has_temp_login is True \
                        and user.temp_login_expiration > now:
                    return user
                user.clear_temp_login()
            return None

        @classmethod
        def get_by_oauth(cls, provider, provider_user_id):
            """
            Get a user by OAuth
            :param provider:
            :param provider_user_id:
            :return: User
            """
            oauth = UserOauthLogin.get_by_provider(
                provider=provider, provider_user_id=provider_user_id)
            return oauth.user if oauth else None

        @classmethod
        def new(cls,
                email,
                password=None,
                first_name=None,
                last_name=None,
                role="USER",
                signup_method="email",
                profile_image_url=None,
                **kwargs):
            """
            Create a new user account
            """
            user = cls.get_by_email(email)
            if user:
                raise ModelError("User exists already")
            user = cls.create(email=email,
                              first_name=first_name,
                              last_name=last_name,
                              signup_method=signup_method,
                              profile_image_url=profile_image_url)
            if password:
                user.set_password(password)
            if role:
                role_ = UserRole.get_by_name(role.upper())
                if role_:
                    user.update(role_id=role_.id)

            return user

        @property
        def full_name(self):
            """
            Return the full name
            :return:
            """
            return "%s %s" % (self.first_name, self.last_name)

        @property
        def name(self):
            """
            Alias to first_name
            :return:
            """
            return self.first_name

        def password_matched(self, password):
            """
            Check if the password matched the hash
            :returns bool:
            """
            return utils.verify_encrypted_string(password, self.password_hash)

        def set_password(self, password, random=False):
            """
            Encrypt the password and save it in the DB
            Return the password passed or the new password if randomed
            """
            if random:
                password = utils.generate_random_string()
            self.update(password_hash=utils.encrypt_string(password))
            return password

        def set_temp_login(self, expiration=60):
            """
            Create temp login.
            It will allow to have change password on account
            :param expiration: in minutes the time for expiration
            """
            expiration = datetime.datetime.now() + datetime.timedelta(
                minutes=expiration)
            while True:
                token = utils.generate_random_string(32).lower()
                if not User.all().filter(
                        User.temp_login_token == token).first():
                    break
            self.update(has_temp_login=True,
                        temp_login_token=token,
                        temp_login_expiration=expiration)
            return token

        def clear_temp_login(self):
            self.update(has_temp_login=False,
                        temp_login_token=None,
                        temp_login_expiration=None)

        def add_oauth(self, provider, provider_user_id, **kwargs):
            """
            To attach a user account to an OAUTH login
            :param provider: the name of the provider
            :param provider_user_id: the id
            :param kwargs:
            :return: Return UserOauthLogin
            """
            u = UserOauthLogin.get_by_provider(
                provider=provider, provider_user_id=provider_user_id)
            if u:
                return u
            return UserOauthLogin.create(user_id=self.id,
                                         provider=provider,
                                         provider_user_id=provider_user_id,
                                         **kwargs)

        def has_any_roles(self, *roles):
            """
            Check if user has any of the roles requested
            :param roles: tuple of roles string
            :return: bool
            """
            roles = list(map(utils.slugify, list(roles)))
            for r in UserRole.all().filter(UserRole.name.in_(roles)):
                if r.id == self.role_id:
                    return True
            return False

    class UserOauth(db.Model):
        user_id = db.Column(db.Integer,
                            db.ForeignKey(User.id, ondelete='CASCADE'))
        provider = db.Column(db.String(50), index=True)
        provider_user_id = db.Column(db.String(255))
        name = db.Column(db.String(255))
        email = db.Column(db.String(255))
        profile_image_url = db.Column(db.String(255))
        access_token = db.Column(db.String(255))
        access_key_id = db.Column(db.String(255))
        access_secret_key = db.Column(db.String(255))
        link = db.Column(db.String(255))
        user = db.relationship(User, backref="oauth_logins")

        @classmethod
        def get_by_provider(cls, provider, provider_user_id):
            """
            Returns the entry of the provider and user id
            :params provider: str - the provider name
            :params provider_user_id: 
            """
            return cls.all()\
                .filter(cls.provider == provider)\
                .filter(cls.provider_user_id == provider_user_id)\
                .first()

    return utils.to_struct(User=User, Role=UserRole, OAuth=UserOauth)
Example #4
0
def model(db):

    class UserRole(db.Model):

        name = db.Column(db.String(75), index=True)
        level = db.Column(db.Integer, index=True)

        @classmethod
        def new(cls, name, level):
            name = utils.slugify(name)
            role = cls.get_by_name(name)
            if not role:
                role = cls.create(name=name, level=level)
            return role

        @classmethod
        def get_by_name(cls, name):
            name = utils.slugify(name)
            return cls.all().filter(cls.name == name).first()

        @classmethod
        def get_by_level(cls, level):
            return cls.all().filter(cls.level == level).first()

    class User(db.Model, UserMixin):

        role_id = db.Column(db.Integer, db.ForeignKey(UserRole.id))
        email = db.Column(db.String(75), index=True, unique=True)
        email_confirmed = db.Column(db.Boolean, default=False)
        password_hash = db.Column(db.String(255))
        has_temp_login = db.Column(db.Boolean, default=False)
        temp_login_token = db.Column(db.String(100), index=True)
        temp_login_expiration = db.Column(db.DateTime)
        first_name = db.Column(db.String(255))
        last_name = db.Column(db.String(255))
        date_of_birth = db.Column(db.Date)
        sex = db.Column(db.String(10))   # To get confusion out of the way, Sex refers to natural/biological features.
        profile_image_url = db.Column(db.String(255))
        signup_method = db.Column(db.String(255))
        active = db.Column(db.Boolean, default=True, index=True)
        last_login = db.Column(db.DateTime)
        last_visited = db.Column(db.DateTime)
        role = db.relationship(UserRole)

        # ------ FLASK-LOGIN REQUIRED METHODS ----------------------------------

        @property
        def is_active(self):
            return self.active

        # ---------- END FLASK-LOGIN REQUIREMENTS ------------------------------

        @classmethod
        def get_by_email(cls, email):
            """
            Return a User by email address
            """
            return cls.all().filter(cls.email == email).first()

        @classmethod
        def get_by_temp_login(cls, token):
            """
            Return a User by temp_login_token
            temp_login_token allows a user to login with the token
            and reset the password
            """
            user = cls.all().filter(cls.temp_login_token == token).first()
            if user:
                now = datetime.datetime.now()
                if user.has_temp_login is True \
                        and user.temp_login_expiration > now:
                    return user
                user.clear_temp_login()
            return None

        @classmethod
        def get_by_oauth(cls, provider, provider_user_id):
            """
            Get a user by OAuth
            :param provider:
            :param provider_user_id:
            :return: User
            """
            oauth = UserOauthLogin.get_by_provider(provider=provider,
                                                   provider_user_id=provider_user_id)
            return oauth.user if oauth else None
        
        @classmethod
        def new(cls,
                email,
                password=None,
                first_name=None,
                last_name=None,
                role="USER",
                signup_method="email",
                profile_image_url=None,
                **kwargs):
            """
            Create a new user account
            """
            user = cls.get_by_email(email)
            if user:
                raise ModelError("User exists already")
            user = cls.create(email=email,
                              first_name=first_name,
                              last_name=last_name,
                              signup_method=signup_method,
                              profile_image_url=profile_image_url)
            if password:
                user.set_password(password)
            if role:
                role_ = UserRole.get_by_name(role.upper())
                if role_:
                    user.update(role_id=role_.id)

            return user

        @property
        def full_name(self):
            """
            Return the full name
            :return:
            """
            return "%s %s" % (self.first_name, self.last_name)

        @property
        def name(self):
            """
            Alias to first_name
            :return:
            """
            return self.first_name

        def password_matched(self, password):
            """
            Check if the password matched the hash
            :returns bool:
            """
            return utils.verify_encrypted_string(password, self.password_hash)

        def set_password(self, password, random=False):
            """
            Encrypt the password and save it in the DB
            Return the password passed or the new password if randomed
            """
            if random:
                password = utils.generate_random_string()
            self.update(password_hash=utils.encrypt_string(password))
            return password

        def set_temp_login(self, expiration=60):
            """
            Create temp login.
            It will allow to have change password on account
            :param expiration: in minutes the time for expiration
            """
            expiration = datetime.datetime.now() + datetime.timedelta(minutes=expiration)
            while True:
                token = utils.generate_random_string(32).lower()
                if not User.all().filter(User.temp_login_token == token).first():
                    break
            self.update(has_temp_login=True,
                        temp_login_token=token,
                        temp_login_expiration=expiration)
            return token

        def clear_temp_login(self):
            self.update(has_temp_login=False,
                        temp_login_token=None,
                        temp_login_expiration=None)

        def add_oauth(self, provider, provider_user_id, **kwargs):
            """
            To attach a user account to an OAUTH login
            :param provider: the name of the provider
            :param provider_user_id: the id
            :param kwargs:
            :return: Return UserOauthLogin
            """
            u = UserOauthLogin.get_by_provider(provider=provider,
                                               provider_user_id=provider_user_id)
            if u:
                return u
            return UserOauthLogin.create(user_id=self.id,
                                         provider=provider,
                                         provider_user_id=provider_user_id,
                                         **kwargs)

        def has_any_roles(self, *roles):
            """
            Check if user has any of the roles requested
            :param roles: tuple of roles string
            :return: bool
            """
            roles = map(utils.slugify, list(roles))
            for r in UserRole.all().filter(UserRole.name.in_(roles)):
                if r.id == self.role_id:
                    return True
            return False

    class UserOauth(db.Model):
        user_id = db.Column(db.Integer, db.ForeignKey(User.id, ondelete='CASCADE'))
        provider = db.Column(db.String(50), index=True)
        provider_user_id = db.Column(db.String(255))
        name = db.Column(db.String(255))
        email = db.Column(db.String(255))
        profile_image_url = db.Column(db.String(255))
        access_token = db.Column(db.String(255))
        access_key_id = db.Column(db.String(255))
        access_secret_key = db.Column(db.String(255))
        link = db.Column(db.String(255))
        user = db.relationship(User, backref="oauth_logins")

        @classmethod
        def get_by_provider(cls, provider, provider_user_id):
            """
            Returns the entry of the provider and user id
            :params provider: str - the provider name
            :params provider_user_id: 
            """
            return cls.all()\
                .filter(cls.provider == provider)\
                .filter(cls.provider_user_id == provider_user_id)\
                .first()

    return utils.to_struct(User=User,
                           Role=UserRole,
                           OAuth=UserOauth)
Example #5
0
def test_to_struct():
    s = utils.to_struct(n="Hello", b="Bye")
    assert s.n == "Hello"