拉黑后端实现

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

初衷

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

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

策略

  • 删除私信时勾选拉黑:把对方加入自己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 = ['[email protected]']
            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/', 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!

你可能感兴趣的:(拉黑,kvdb)