Exemple #1
0
class Post(db.Model):

    __tablename__ = "posts"

    PUBLIC = 100
    FRIENDS = 200
    PRIVATE = 300

    PER_PAGE = 40

    query_class = PostQuery

    id = db.Column(db.Integer, primary_key=True)

    author_id = db.Column(db.Integer,
                          db.ForeignKey(User.id, ondelete='CASCADE'),
                          nullable=False)

    title = db.Column(db.Unicode(200))
    description = db.Column(db.UnicodeText)
    link = db.Column(db.String(250))
    date_created = db.Column(db.DateTime, default=datetime.utcnow)
    score = db.Column(db.Integer, default=1)
    num_comments = db.Column(db.Integer, default=0)
    votes = db.Column(DenormalizedText)
    access = db.Column(db.Integer, default=PUBLIC)

    _tags = db.Column("tags", db.UnicodeText)

    author = db.relation(User, innerjoin=True, lazy="joined")

    __mapper_args__ = {'order_by': id.desc()}

    class Permissions(object):
        def __init__(self, obj):
            self.obj = obj

        @cached_property
        def default(self):
            return Permission(UserNeed(self.obj.author_id)) & moderator

        @cached_property
        def view(self):
            if self.obj.access == Post.PUBLIC:
                return Permission()

            if self.obj.access == Post.FRIENDS:
                needs = [
                    UserNeed(user_id) for user_id in self.obj.author.friends
                ]

                return self.default & Permission(*needs)

            return self.default

        @cached_property
        def edit(self):
            return self.default

        @cached_property
        def delete(self):
            return self.default

        @cached_property
        def vote(self):

            needs = [UserNeed(user_id) for user_id in self.obj.votes]
            needs.append(UserNeed(self.obj.author_id))

            return auth & Denial(*needs)

        @cached_property
        def comment(self):
            return auth

    def __init__(self, *args, **kwargs):
        super(Post, self).__init__(*args, **kwargs)
        self.votes = self.votes or set()
        self.access = self.access or self.PUBLIC

    def __str__(self):
        return self.title

    def __repr__(self):
        return "<%s>" % self

    @cached_property
    def permissions(self):
        return self.Permissions(self)

    def vote(self, user):
        self.votes.add(user.id)

    def _get_tags(self):
        return self._tags

    def _set_tags(self, tags):

        self._tags = tags

        if self.id:
            # ensure existing tag references are removed
            d = db.delete(post_tags, post_tags.c.post_id == self.id)
            db.engine.execute(d)

        for tag in set(self.taglist):

            slug = slugify(tag)

            tag_obj = Tag.query.filter(Tag.slug == slug).first()
            if tag_obj is None:
                tag_obj = Tag(name=tag, slug=slug)
                db.session.add(tag_obj)

            if self not in tag_obj.posts:
                tag_obj.posts.append(self)

    tags = db.synonym("_tags", descriptor=property(_get_tags, _set_tags))

    @property
    def taglist(self):
        if self.tags is None:
            return []

        tags = [t.strip() for t in self.tags.split(",")]
        return [t for t in tags if t]

    @cached_property
    def linked_taglist(self):
        """
        Returns the tags in the original order and format, 
        with link to tag page
        """
        return [(tag, url_for('frontend.tag', slug=slugify(tag)))
                for tag in self.taglist]

    @cached_property
    def domain(self):
        if not self.link:
            return ''
        return domain(self.link)

    @cached_property
    def json(self):
        """
        Returns dict of safe attributes for passing into 
        a JSON request.
        """

        return dict(post_id=self.id,
                    score=self.score,
                    title=self.title,
                    link=self.link,
                    description=self.description,
                    num_comments=self.num_comments,
                    author=self.author.username)

    @cached_property
    def access_name(self):
        return {
            Post.PUBLIC: "public",
            Post.FRIENDS: "friends",
            Post.PRIVATE: "private"
        }.get(self.access, "public")

    def can_access(self, user=None):
        if self.access == self.PUBLIC:
            return True

        if user is None:
            return False

        if user.is_moderator or user.id == self.author_id:
            return True

        return self.access == self.FRIENDS and self.author_id in user.friends

    @cached_property
    def comments(self):
        """
        Returns comments in tree. Each parent comment has a "comments" 
        attribute appended and a "depth" attribute.
        """
        from newsmeme.models.comments import Comment

        comments = Comment.query.filter(Comment.post_id == self.id).all()

        def _get_comments(parent, depth):

            parent.comments = []
            parent.depth = depth

            for comment in comments:
                if comment.parent_id == parent.id:
                    parent.comments.append(comment)
                    _get_comments(comment, depth + 1)

        parents = [c for c in comments if c.parent_id is None]

        for parent in parents:
            _get_comments(parent, 0)

        return parents

    def _url(self, _external=False):
        return url_for('post.view',
                       post_id=self.id,
                       slug=self.slug,
                       _external=_external)

    @cached_property
    def url(self):
        return self._url()

    @cached_property
    def permalink(self):
        return self._url(True)

    @cached_property
    def markdown(self):
        return Markup(markdown(self.description or ''))

    @cached_property
    def slug(self):
        return slugify(self.title or '')[:80]
Exemple #2
0
class User(db.Model):

    __tablename__ = "users"

    query_class = UserQuery

    # user roles
    MEMBER = 100
    MODERATOR = 200
    ADMIN = 300

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.Unicode(60), unique=True, nullable=False)
    email = db.Column(db.String(150), unique=True, nullable=False)
    karma = db.Column(db.Integer, default=0)
    date_joined = db.Column(db.DateTime, default=datetime.utcnow)
    activation_key = db.Column(db.String(80), unique=True)
    role = db.Column(db.Integer, default=MEMBER)
    receive_email = db.Column(db.Boolean, default=False)
    email_alerts = db.Column(db.Boolean, default=False)
    followers = db.Column(DenormalizedText)
    following = db.Column(DenormalizedText)

    _password = db.Column("password", db.String(80))
    _openid = db.Column("openid", db.String(80), unique=True)

    class Permissions(Permissions):
        @cached_property
        def send_message(self):
            if not self.receive_email:
                return null

            needs = [UserNeed(user_id) for user_id in self.friends]
            if not needs:
                return null

            return Permission(*needs)

    def __init__(self, *args, **kwargs):
        super(User, self).__init__(*args, **kwargs)
        self.followers = self.followers or set()
        self.following = self.following or set()

    def __str__(self):
        return self.username

    def __repr__(self):
        return "<%s>" % self

    @cached_property
    def permissions(self):
        return self.Permissions(self)

    def _get_password(self):
        return self._password

    def _set_password(self, password):
        self._password = generate_password_hash(password)

    password = db.synonym("_password",
                          descriptor=property(_get_password, _set_password))

    def check_password(self, password):
        if self.password is None:
            return False
        return check_password_hash(self.password, password)

    def _get_openid(self):
        return self._openid

    def _set_openid(self, openid):
        self._openid = generate_password_hash(openid)

    openid = db.synonym("_openid",
                        descriptor=property(_get_openid, _set_openid))

    def check_openid(self, openid):
        if self.openid is None:
            return False
        return check_password_hash(self.openid, openid)

    @cached_property
    def provides(self):
        needs = [RoleNeed('authenticated'), UserNeed(self.id)]

        if self.is_moderator:
            needs.append(RoleNeed('moderator'))

        if self.is_admin:
            needs.append(RoleNeed('admin'))

        return needs

    @cached_property
    def num_followers(self):
        if self.followers:
            return len(self.followers)
        return 0

    @cached_property
    def num_following(self):
        return len(self.following)

    def is_following(self, user):
        return user.id in self.following

    @property
    def friends(self):
        return self.following.intersection(self.followers)

    def is_friend(self, user):
        return user.id in self.friends

    def get_friends(self):
        return User.query.filter(User.id.in_(self.friends))

    def follow(self, user):

        user.followers.add(self.id)
        self.following.add(user.id)

    def unfollow(self, user):
        if self.id in user.followers:
            user.followers.remove(self.id)

        if user.id in self.following:
            self.following.remove(user.id)

    def get_following(self):
        """
        Return following users as query
        """
        return User.query.filter(User.id.in_(self.following or set()))

    def get_followers(self):
        """
        Return followers as query
        """
        return User.query.filter(User.id.in_(self.followers or set()))

    @property
    def is_moderator(self):
        return self.role >= self.MODERATOR

    @property
    def is_admin(self):
        return self.role >= self.ADMIN

    @cached_property
    def gravatar(self):
        if not self.email:
            return ''
        md5 = hashlib.md5()
        md5.update(self.email.strip().lower())
        return md5.hexdigest()

    def gravatar_url(self, size=80):
        if not self.gravatar:
            return ''

        return "http://www.gravatar.com/avatar/%s.jpg?s=%d" % (self.gravatar,
                                                               size)