Flask Vue.js全栈开发|第11章:私信

  • 原创
  • Madman
  • /
  • /
  • 0
  • 1841 次阅读

flask vuejs 全栈开发-min.png

Synopsis: 上一篇文章中用户收到的新评论通知有些问题,没考虑到评论被回复的情况,本文将修复这个 BUG。除了在用户发布的文章下面评论进行互动以外,用户之间还可以发送私密的信息,别人无法看到,类似于网络聊天。目前,用户之间可以随意发送私信,如果有人骚扰你,你也只能默默接收这些垃圾私信,下一篇将实现 黑名单 功能,可以屏蔽你讨厌的用户,对方无法 Follow 你,不会收到你新文章提醒,你也不会收到对方的骚扰信息

代码已上传到 https://github.com/wangy8961/flask-vuejs-madblog/tree/v0.11 ,欢迎star

1. 修复 BUG

修改 back-end/app/models.py

class User(PaginatedAPIMixin, db.Model):
    ...
    def new_recived_comments(self):
        '''用户收到的新评论计数
        包括:
        1. 用户的所有文章下面新增的评论
        2. 用户发表的评论(或下面的子孙)被人回复了
        '''
        last_read_time = self.last_recived_comments_read_time or datetime(1900, 1, 1)
        # 用户发布的所有文章
        user_posts_ids = [post.id for post in self.posts.all()]
        # 用户文章下面的新评论, 即评论的 post_id 在 user_posts_ids 集合中,且评论的 author 不是自己(文章的作者)
        q1 = set(Comment.query.filter(Comment.post_id.in_(user_posts_ids), Comment.author != self).all())

        # 用户发表的评论被人回复了,找到每个用户评论的所有子孙
        q2 = set()
        for c in self.comments:
            q2 = q2 | c.get_descendants()
        q2 = q2 - set(self.comments.all())  # 除去子孙中,用户自己发的(因为是多级评论,用户可能还会在子孙中盖楼),自己回复的不用通知
        # 用户收到的总评论集合为 q1 与 q2 的并集
        recived_comments = q1 | q2
        # 最后,再过滤掉 last_read_time 之前的评论
        return len([c for c in recived_comments if c.timestamp > last_read_time])
    ...

同时,修改发表评论和删除评论的 API:

@bp.route('/comments/', methods=['POST'])
@token_auth.login_required
def create_comment():
    '''在某篇博客文章下面发表新评论'''
    data = request.get_json()
    if not data:
        return bad_request('You must post JSON data.')
    if 'body' not in data or not data.get('body').strip():
        return bad_request('Body is required.')
    if 'post_id' not in data or not data.get('post_id'):
        return bad_request('Post id is required.')

    post = Post.query.get_or_404(int(data.get('post_id')))
    comment = Comment()
    comment.from_dict(data)
    comment.author = g.current_user
    comment.post = post
    # 必须先添加该评论,后续给各用户发送通知时,User.new_recived_comments() 才能是更新后的值
    db.session.add(comment)
    db.session.commit()  # 更新数据库,添加评论记录
    # 添加评论时:
    # 1. 如果是一级评论,只需要给文章作者发送新评论通知
    # 2. 如果不是一级评论,则需要给文章作者和该评论的所有祖先的作者发送新评论通知
    users = set()
    users.add(comment.post.author)  # 将文章作者添加进集合中
    if comment.parent:
        ancestors_authors = {c.author for c in comment.get_ancestors()}
        users = users | ancestors_authors
    # 给各用户发送新评论通知
    for u in users:
        u.add_notification('unread_recived_comments_count',
                           u.new_recived_comments())
    db.session.commit()  # 更新数据库,写入新通知
    response = jsonify(comment.to_dict())
    response.status_code = 201
    # HTTP协议要求201响应包含一个值为新资源URL的Location头部
    response.headers['Location'] = url_for('api.get_comment', id=comment.id)
    return response


@bp.route('/comments/<int:id>', methods=['DELETE'])
@token_auth.login_required
def delete_comment(id):
    '''删除单个评论'''
    comment = Comment.query.get_or_404(id)
    if g.current_user != comment.author and g.current_user != comment.post.author:
        return error_response(403)
    # 删除评论时:
    # 1. 如果是一级评论,只需要给文章作者发送新评论通知
    # 2. 如果不是一级评论,则需要给文章作者和该评论的所有祖先的作者发送新评论通知
    users = set()
    users.add(comment.post.author)  # 将文章作者添加进集合中
    if comment.parent:
        ancestors_authors = {c.author for c in comment.get_ancestors()}
        users = users | ancestors_authors
    # 必须先删除该评论,后续给各用户发送通知时,User.new_recived_comments() 才能是更新后的值
    db.session.delete(comment)
    db.session.commit()  # 更新数据库,删除评论记录
    # 给各用户发送新评论通知
    for u in users:
        u.add_notification('unread_recived_comments_count',
                           u.new_recived_comments())
    db.session.commit()  # 更新数据库,写入新通知
    return '', 204

2. 用户私信

2.1 数据模型

修改 back-end/app/models.py,增加 Message 数据模型:

class User(PaginatedAPIMixin, db.Model):
    ...
    # 用户发送的私信
    messages_sent = db.relationship('Message', foreign_keys='Message.sender_id',
                                    backref='sender', lazy='dynamic',
                                    cascade='all, delete-orphan')
    # 用户接收的私信
    messages_received = db.relationship('Message',
                                        foreign_keys='Message.recipient_id',
                                        backref='recipient', lazy='dynamic',
                                        cascade='all, delete-orphan')
    # 用户最后一次查看私信的时间
    last_messages_read_time = db.Column(db.DateTime)
    ...

    def new_recived_messages(self):
        '''用户未读的私信计数'''
        last_read_time = self.last_messages_read_time or datetime(1900, 1, 1)
        return Message.query.filter_by(recipient=self).filter(
            Message.timestamp > last_read_time).count()


class Message(PaginatedAPIMixin, db.Model):
    __tablename__ = 'messages'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    sender_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    recipient_id = db.Column(
                                
                            
分类: Vue.js
标签: 私信 API RESTful vuejs flask
未经允许不得转载: LIFE & SHARE - 王颜公子 » Flask Vue.js全栈开发|第11章:私信

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.