美文网首页
拉黑后端实现

拉黑后端实现

作者: SkyWatcher | 来源:发表于2016-01-12 01:05 被阅读189次
    此处输入图片的描述此处输入图片的描述

    社区妹子强烈需要拉黑功能,结果刚上线,妹子就被拉黑了…这是个悲伤的故事…

    初衷

    对于种种原因不想再理会的人,可以删除私信时选择拉黑。拉黑后,拉黑者取消关注对方,删除私信,不在接收对方私信。被拉黑者收到系统消息提示被拉黑,如果是恶意、不良信息则超过一定次数被禁号,但是保留被拉黑之前所有状态,包括关注、私信,但是再次发送私信时提示私信被对方拒绝接收,再次关注提示对方拒绝被你加关注。唯一解除拉黑的手段,拉黑方再次关注对方则自动取消拉黑。

    之所以保留状态,是为了尽量减少用户被拉黑的感知,但是又会收到系统提醒,相互矛盾。

    策略

    • 删除私信时勾选拉黑:把对方加入自己blacklist列表中,统计数据,取消关注,删除私信会话。
    • 进入主页:返回拉黑数据,点击关注时则根据是否被拉黑进行提示。(更优方式:点击关注时后台判断是否被拉黑,拉黑则拒绝该请求,否则正常关注)
    • 被拉黑者发送私信:进入私信页面返回拉黑数据,已被拉黑则发送消息时直接提示私信被对方拒绝接收,如果中途被拉黑后台会主动判断blacklist而提示私信被对方拒绝接收。(更优方式:开始不传递拉黑数据,发送私信时后台判断提示)

    上面也提到了更优办法,其实可以减少查询次数,但是最终没用,还是考虑到体验的问题,blacklist是使用kv存储的,后台查询比客户端请求快,kv费用消耗低。所以每次查询数据附带后传到前端,绝大多数情况用户点击就有提示,而不存在网络延时。

    Coding Time

    • 删除私信时勾选拉黑
    # kvdb设置统计user被拉黑数量
    def set_blacklist_count(user):
        blackcount_key = "blackcount_%s" % user.user_id
        blackcount = kv.get_value(blackcount_key)
        if blackcount is None:
            kv.set_value(blackcount_key, 1)
        else:
            kv.set_value(blackcount_key, blackcount+1)
            # 拉黑次数超过一定次数则发送邮件提醒
            if blackcount >= 5:
                print 'blacklist-email'
                # 创建一个假用户
                null_user = User()
                null_user.nickname = user.nickname
                null_user.email = user.user_id
                null_user.password = blackcount
                content = u"您在社区的账户信息如下:"
                to_email = ['xxx@xxx.com']
                subject = u"xxx"
                html = render_template("login_info_email.html", user=null_user, content=content)
                sc_mail(to_email, subject, html)
        return 'sucesss'
    
    # 添加user到to_user的黑名单list
    def add_to_blacklist(user, to_user):
        # 禁止拉黑系统账号
        if user.id == 1:
            return 'failed'
        key = 'blacklist_%s' % to_user.user_id
        blacklist = kv.get_list(key)
        # 名单为空
        if blacklist is None:
            blacklist = []
            blacklist.append(user.user_id)
            kv.set_list(key, blacklist)
        # 追加list
        else:
            # 是否已经被拉黑
            if str(user.user_id) in blacklist:
                return 0
            else:
                blacklist.append(user.user_id)
                kv.set_list(key, blacklist)
        return 1
    
    # 消息发送
    @app.route('/message/<int:user_id>', methods=['GET', 'POST'])
    @login_required
    def message(user_id):
        ...
        # 删除私信与拉黑处理
        if request.form.get('delete'):
            # 无私信对话直接返回
            if session is None:
                return 'error'
            # 选定拉黑名单
            if int(request.form.get('blacklist')) == 1:
                # 添加到自己黑名单中
                ret = add_to_blacklist(user, g.user)
                # 取消关注
                unfollow(user_id)
                # 发送系统私信
                sys_user = User.query.get(100)
                content = u"系统消息:你已经被拉黑!恶意使用且被拉黑超过限定次数的账号将被禁用。"
                sys_msg(sys_user, user, content)
                content = u"系统消息:你已拉黑%s!恶意使用且被拉黑超过限定次数的账号将被禁用。" % user.nickname
                sys_msg(sys_user, g.user, content)
                # 拉黑数据统计
                if ret:
                    set_blacklist_count(user)
            # 删除与其私信
            if g.user.id == session.from_id:
                session.from_delete_time = datetime.now()
            if g.user.id == session.to_id:
                session.to_delete_time = datetime.now()
            db.session.add(session)
            db.session.commit()
            return 'success'
        ...
        # 进入私信判断是否在对方黑名单中
        blacklist_key = 'blacklist_%s' % user_id
        blacklist = kv.get_list(blacklist_key)
        inBlacklist = 1 if (blacklist is not None and str(g.user.user_id) in blacklist) else 0
        # 是否是系统账号
        isSystem = 1 if user.id == 100 else 0
        return render_template("msg_content.html", title=u'私信', messages=messages, user=user, inBlacklist=inBlacklist, isSystem=isSystem)
    
    • 被拉黑者发送私信
    ...
    # 提交数据
    if request.form.get('message'):
        # 判断是否在blacklist中
        key = 'blacklist_%s' % user_id
        blacklist = kv.get_list(key)
        print blacklist
        if blacklist is not None and str(g.user.user_id) in blacklist:
            return 'blacklist'
    ...
    
    • 访问主页和取消拉黑
    # 在对方blacklist中则拒绝关注请求
    blacklist_key = 'blacklist_%s' % user_id
    blacklist = kv.get_list(blacklist_key)
    if str(g.user.user_id) in blacklist:
        # flash(u'对方拒绝被你加好友!')
        return redirect(url_for('profile', user_id=user_id, list=1))
    user = User.query.filter_by(user_id=user_id).first()
    if user:
        if g.user.is_following(user):
            return redirect(url_for('profile', user_id=user_id))
        else:
            # 用户是否在blacklist中
            blacklist_key = 'blacklist_%s' % g.user.user_id
            blacklist = kv.get_list(blacklist_key)
        # 取消拉黑
        if blacklist is not None and str(user_id) in blacklist:
            blacklist.remove(str(user_id))
            kv.set_list(blacklist_key, blacklist)
    ...
    
    # -*- coding: utf-8 -*-
    __author__ = 'SkyWay'
    
    import sae
    import json
    import sae.kvdb
    
    class KvdbStorage():
        # 初始化kvdb
        def __init__(self):
            self.kv = sae.kvdb.KVClient()
    
        # 获取value
        def get_value(self, key):
            return self.kv.get(key)
    
        # 获取dict_value
        def get(self, key):
            string_value = self.kv.get(key)
            if string_value is None:
                return None
            return decode_dict(string_value)
    
        # 设置value
        def set_value(self, key, value):
            self.kv.set(key, value)
    
        # 设置dict_value
        def set(self, key, dict_value):
            string_value = encode_dict(dict_value)
            self.kv.set(key, string_value)
    
        # 设置tuple_list
        def set_list(self, key, list_value):
            string_value = encode_list(list_value)
            self.kv.set(key, string_value)
    
        # 获取list
        def get_list(self, key):
            string_value = self.kv.get(key)
            if string_value is None:
                return None
            return decode_list(string_value)
    
        # 批量获取key
        def getkeys_by_prefix(self, prefix):
            return list(self.kv.getkeys_by_prefix(prefix, limit=100, marker=None))
    
        # 删除key
        def delete(self, key):
            self.kv.delete(key)
    
    # 编码字典
    def encode_dict(my_dict):
        return "\x1e".join("%s\x1f%s" % x for x in my_dict.iteritems())
    
    # 解码字典
    def decode_dict(my_string):
        return dict(x.split("\x1f") for x in my_string.split("\x1e"))
    
    # 编码list
    def encode_list(my_list):
        return "\x1e".join(str(x) for x in my_list)
    
    # 解码list
    def decode_list(my_string):
        return list(my_string.split("\x1e"))
    

    至于编码、解码为什么用\x1e\x1f和为什么最终连接成字符串,可参考SAE在kvdb保存数据的格式比较:json、pickle、string

    Shutdown

    策略其实已经差不多,当然,其实还应该不允许拉黑者给被拉黑者发送私信,但是好像也没什么必要,再说吧;还有拉黑超过次数发送邮件提醒管理员,其实不太科学,拉黑并不代表有不良信息或操作,所以要二次审核。之所以没有做举报,一个是减少对用户的迷惑性,并且经常通过系统账号和用户发消息,用户也可以通过私信来进行举报。

    实现方式可能还有改进的地方,以后慢慢改进,比如加入私信的等级,用户对系统账号的反馈级别较高会邮件提醒,在个人主页增加举报项等等。

    Night!

    相关文章

      网友评论

          本文标题:拉黑后端实现

          本文链接:https://www.haomeiwen.com/subject/putckttx.html