社區(qū)妹子強(qiáng)烈需要拉黑功能芥玉,結(jié)果剛上線,妹子就被拉黑了…這是個(gè)悲傷的故事…
初衷
對于種種原因不想再理會的人急迂,可以刪除私信時(shí)選擇拉黑影所。拉黑后,拉黑者取消關(guān)注對方僚碎,刪除私信猴娩,不在接收對方私信。被拉黑者收到系統(tǒng)消息提示被拉黑勺阐,如果是惡意卷中、不良信息則超過一定次數(shù)被禁號
,但是保留被拉黑之前所有狀態(tài)渊抽,包括關(guān)注蟆豫、私信,但是再次發(fā)送私信時(shí)提示私信被對方拒絕接收
懒闷,再次關(guān)注提示對方拒絕被你加關(guān)注
十减。唯一解除拉黑的手段,拉黑方再次關(guān)注對方則自動取消拉黑毛雇。
之所以保留狀態(tài)嫉称,是為了盡量減少用戶被拉黑的感知,但是又會收到系統(tǒng)提醒灵疮,相互矛盾织阅。
策略
- 刪除私信時(shí)勾選拉黑:把對方加入自己blacklist列表中,統(tǒng)計(jì)數(shù)據(jù)震捣,取消關(guān)注荔棉,刪除私信會話。
- 進(jìn)入主頁:返回拉黑數(shù)據(jù)蒿赢,點(diǎn)擊關(guān)注時(shí)則根據(jù)是否被拉黑進(jìn)行提示润樱。(更優(yōu)方式:點(diǎn)擊關(guān)注時(shí)后臺判斷是否被拉黑,拉黑則拒絕該請求羡棵,否則正常關(guān)注)
- 被拉黑者發(fā)送私信:進(jìn)入私信頁面返回拉黑數(shù)據(jù)壹若,已被拉黑則發(fā)送消息時(shí)直接提示
私信被對方拒絕接收
,如果中途被拉黑后臺會主動判斷blacklist而提示私信被對方拒絕接收
皂冰。(更優(yōu)方式:開始不傳遞拉黑數(shù)據(jù)店展,發(fā)送私信時(shí)后臺判斷提示)
上面也提到了更優(yōu)辦法,其實(shí)可以減少查詢次數(shù)秃流,但是最終沒用赂蕴,還是考慮到體驗(yàn)的問題,blacklist是使用kv存儲的舶胀,后臺查詢比客戶端請求快概说,kv費(fèi)用消耗低碧注。所以每次查詢數(shù)據(jù)附帶后傳到前端,絕大多數(shù)情況用戶點(diǎn)擊就有提示糖赔,而不存在網(wǎng)絡(luò)延時(shí)萍丐。
Coding Time
- 刪除私信時(shí)勾選拉黑
# kvdb設(shè)置統(tǒng)計(jì)user被拉黑數(shù)量
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)
# 拉黑次數(shù)超過一定次數(shù)則發(fā)送郵件提醒
if blackcount >= 5:
print 'blacklist-email'
# 創(chuàng)建一個(gè)假用戶
null_user = User()
null_user.nickname = user.nickname
null_user.email = user.user_id
null_user.password = blackcount
content = u"您在社區(qū)的賬戶信息如下:"
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):
# 禁止拉黑系統(tǒng)賬號
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:
# 是否已經(jīng)被拉黑
if str(user.user_id) in blacklist:
return 0
else:
blacklist.append(user.user_id)
kv.set_list(key, blacklist)
return 1
# 消息發(fā)送
@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)
# 取消關(guān)注
unfollow(user_id)
# 發(fā)送系統(tǒng)私信
sys_user = User.query.get(100)
content = u"系統(tǒng)消息:你已經(jīng)被拉黑!惡意使用且被拉黑超過限定次數(shù)的賬號將被禁用放典。"
sys_msg(sys_user, user, content)
content = u"系統(tǒng)消息:你已拉黑%s碉纺!惡意使用且被拉黑超過限定次數(shù)的賬號將被禁用。" % user.nickname
sys_msg(sys_user, g.user, content)
# 拉黑數(shù)據(jù)統(tǒng)計(jì)
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'
...
# 進(jìn)入私信判斷是否在對方黑名單中
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
# 是否是系統(tǒng)賬號
isSystem = 1 if user.id == 100 else 0
return render_template("msg_content.html", title=u'私信', messages=messages, user=user, inBlacklist=inBlacklist, isSystem=isSystem)
- 被拉黑者發(fā)送私信
...
# 提交數(shù)據(jù)
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中則拒絕關(guān)注請求
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)
...
- kv存取部分
之前的圖床——基于七牛JS-SDK和KVDB已經(jīng)提到過,只是做了list的補(bǔ)充耿导。
# -*- 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)
# 設(shè)置value
def set_value(self, key, value):
self.kv.set(key, value)
# 設(shè)置dict_value
def set(self, key, dict_value):
string_value = encode_dict(dict_value)
self.kv.set(key, string_value)
# 設(shè)置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保存數(shù)據(jù)的格式比較:json舱呻、pickle醋火、string
Shutdown
策略其實(shí)已經(jīng)差不多,當(dāng)然箱吕,其實(shí)還應(yīng)該不允許拉黑者給被拉黑者發(fā)送私信芥驳,但是好像也沒什么必要,再說吧茬高;還有拉黑超過次數(shù)發(fā)送郵件提醒管理員兆旬,其實(shí)不太科學(xué),拉黑并不代表有不良信息或操作怎栽,所以要二次審核丽猬。之所以沒有做舉報(bào),一個(gè)是減少對用戶的迷惑性熏瞄,并且經(jīng)常通過系統(tǒng)賬號和用戶發(fā)消息脚祟,用戶也可以通過私信來進(jìn)行舉報(bào)。
實(shí)現(xiàn)方式可能還有改進(jìn)的地方强饮,以后慢慢改進(jìn)由桌,比如加入私信的等級,用戶對系統(tǒng)賬號的反饋級別較高會郵件提醒邮丰,在個(gè)人主頁增加舉報(bào)項(xiàng)等等行您。
Night!