Browse Source

自定义头衔

master
hole-thu 4 years ago
parent
commit
e8ef07cceb
  1. 5
      clear_redis.py
  2. 45
      hole.py
  3. 2
      models.py
  4. 8
      utils.py

5
clear_redis.py

@ -0,0 +1,5 @@
# 每次重置时执行
from utils import rds, RDS_KEY_TITLE, RDS_KEY_BLOCKED_COUNT
rds.delete(RDS_KEY_BLOCKED_COUNT)
rds.delete(RDS_KEY_TITLE)

45
hole.py

@ -10,7 +10,7 @@ from sqlalchemy.sql.expression import func
from mastodon import Mastodon from mastodon import Mastodon
from models import db, User, Post, Comment, Attention, TagRecord, Syslog from models import db, User, Post, Comment, Attention, TagRecord, Syslog
from utils import get_current_username, map_post, map_comment, map_syslog, check_attention, hash_name, look, get_num, tmp_token, is_admin, check_can_del, rds, RDS_KEY_POLL_OPTS, RDS_KEY_POLL_VOTES, gen_poll_dict, name_with_tmp_limit, RDS_KEY_BLOCK_SET, RDS_KEY_BLOCKED_COUNT, RDS_KEY_DANGEROUS_USERS from utils import get_current_username, map_post, map_comment, map_syslog, check_attention, hash_name, look, get_num, tmp_token, is_admin, check_can_del, rds, RDS_KEY_POLL_OPTS, RDS_KEY_POLL_VOTES, gen_poll_dict, name_with_tmp_limit, RDS_KEY_BLOCK_SET, RDS_KEY_BLOCKED_COUNT, RDS_KEY_DANGEROUS_USERS, RDS_KEY_TITLE
app = Flask(__name__) app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hole.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hole.db'
@ -24,7 +24,6 @@ app.config.from_pyfile('config.py')
db.init_app(app) db.init_app(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)
CS_LOGIN_URL = Mastodon(api_base_url=app.config['MASTODON_URL']) \ CS_LOGIN_URL = Mastodon(api_base_url=app.config['MASTODON_URL']) \
.auth_request_url( .auth_request_url(
client_id=app.config['CLIENT_ID'], client_id=app.config['CLIENT_ID'],
@ -41,9 +40,6 @@ limiter = Limiter(
PER_PAGE = 50 PER_PAGE = 50
DANGEROUS_USER_THRESHOLD = 10 DANGEROUS_USER_THRESHOLD = 10
# 重置后旧的被拉黑次数可以丢弃了,但其他仍需要保留
rds.delete(RDS_KEY_BLOCKED_COUNT)
class APIError(Exception): class APIError(Exception):
msg = '未知错误' msg = '未知错误'
@ -138,6 +134,7 @@ def get_list():
return { return {
'code': 0, 'code': 0,
'tmp_token': tmp_token(), 'tmp_token': tmp_token(),
'custom_title': rds.hget(RDS_KEY_TITLE, hash_name(username)),
'count': len(data), 'count': len(data),
'data': data 'data': data
} }
@ -185,8 +182,6 @@ def get_multi():
} }
@app.route('/_api/v1/search') @app.route('/_api/v1/search')
def search(): def search():
username = get_current_username() username = get_current_username()
@ -248,6 +243,7 @@ def do_post():
post_type = request.form.get('type') post_type = request.form.get('type')
cw = request.form.get('cw', '').strip() cw = request.form.get('cw', '').strip()
poll_options = request.form.getlist('poll_options') poll_options = request.form.getlist('poll_options')
use_title = request.form.get('use_title')
if not content or len(content) > 4096 or len(cw) > 32: if not content or len(content) > 4096 or len(cw) > 32:
raise APIError('无内容或超长') raise APIError('无内容或超长')
@ -263,8 +259,10 @@ def do_post():
if max(map(len, poll_options)) > 32: if max(map(len, poll_options)) > 32:
raise APIError('选项过长') raise APIError('选项过长')
name_hash = hash_name(username)
p = Post( p = Post(
name_hash=hash_name(username), name_hash=name_hash,
author_title=rds.hget(RDS_KEY_TITLE, name_hash) if use_title else None,
content=content, content=content,
search_text=search_text, search_text=search_text,
post_type=post_type, post_type=post_type,
@ -351,14 +349,18 @@ def do_comment():
if post.deleted and not check_can_del(username, post.name_hash): if post.deleted and not check_can_del(username, post.name_hash):
abort(451) abort(451)
content = request.form.get('text') content = request.form.get('text', '').strip()
content = content.strip() if content else None if username.startswith('tmp_'):
content = '[tmp]\n' + content if username[:4] == 'tmp_' else content content = '[tmp]\n' + content
if not content or len(content) > 4096: if not content or len(content) > 4096:
abort(422) abort(422)
use_title = request.form.get('use_title')
name_hash = hash_name(username)
c = Comment( c = Comment(
name_hash=hash_name(username), name_hash=name_hash,
author_title=rds.hget(RDS_KEY_TITLE, name_hash) if use_title else None,
content=content, content=content,
) )
post.comments.append(c) post.comments.append(c)
@ -518,6 +520,7 @@ def system_log():
'start_time': app.config['START_TIME'], 'start_time': app.config['START_TIME'],
'salt': look(app.config['SALT']), 'salt': look(app.config['SALT']),
'tmp_token': tmp_token(), 'tmp_token': tmp_token(),
'custom_title': rds.hget(RDS_KEY_TITLE, hash_name(username)),
'data': [map_syslog(s, username) for s in ss] 'data': [map_syslog(s, username) for s in ss]
} }
@ -627,5 +630,23 @@ def block_user_by_target():
} }
@app.route('/_api/v1/title', methods=['POST'])
@limiter.limit("10 / hour; 1 / 2 second")
def set_title():
username = get_current_username()
title = request.form.get('title')
if not title:
rds.hdel(RDS_KEY_TITLE, hash_name(username))
else:
if len(title) > 10:
raise APIError('自定义头衔太长')
if title in rds.hvals(RDS_KEY_TITLE): # 如果未来量大还是另外用个set维护
raise APIError('已经被使用了')
rds.hset(RDS_KEY_TITLE, hash_name(username), title)
return {'code': 0}
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True) app.run(debug=True)

2
models.py

@ -18,6 +18,7 @@ class Post(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name_hash = db.Column(db.String(64)) name_hash = db.Column(db.String(64))
author_title = db.Column(db.String(10))
content = db.Column(db.String(4096)) content = db.Column(db.String(4096))
search_text = db.Column(db.String(4096), default='', index=True) search_text = db.Column(db.String(4096), default='', index=True)
post_type = db.Column(db.String(8)) post_type = db.Column(db.String(8))
@ -44,6 +45,7 @@ class Post(db.Model):
class Comment(db.Model): class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name_hash = db.Column(db.String(64)) name_hash = db.Column(db.String(64))
author_title = db.Column(db.String(10))
content = db.Column(db.String(4096)) content = db.Column(db.String(4096))
timestamp = db.Column(db.Integer) timestamp = db.Column(db.Integer)
deleted = db.Column(db.Boolean, default=False) deleted = db.Column(db.Boolean, default=False)

8
utils.py

@ -14,6 +14,8 @@ RDS_KEY_BLOCK_SET = 'hole_thu:block_list:%s' # key的参数是name而非namehas
RDS_KEY_BLOCKED_COUNT = 'hole_thu:blocked_count' # namehash -> 被拉黑次数 RDS_KEY_BLOCKED_COUNT = 'hole_thu:blocked_count' # namehash -> 被拉黑次数
RDS_KEY_DANGEROUS_USERS = 'hole_thu:dangerous_users' RDS_KEY_DANGEROUS_USERS = 'hole_thu:dangerous_users'
RDS_KEY_TITLE = 'hole_thu:title' # 用户自己设置的专属头衔, namehash -> 头衔
rds = redis.Redis(**RDS_CONFIG) rds = redis.Redis(**RDS_CONFIG)
@ -31,7 +33,7 @@ def tmp_token():
)[5:21] )[5:21]
def get_current_username(): def get_current_username() -> str:
token = request.headers.get('User-Token') or request.args.get('user_token') token = request.headers.get('User-Token') or request.args.get('user_token')
if not token: if not token:
abort(401) abort(401)
@ -72,7 +74,8 @@ def map_post(p, name, mc=50):
'attention': check_attention(name, p.id), 'attention': check_attention(name, p.id),
'can_del': check_can_del(name, p.name_hash), 'can_del': check_can_del(name, p.name_hash),
'allow_search': bool(p.search_text), 'allow_search': bool(p.search_text),
'poll': None if blocked else gen_poll_dict(p.id, name) 'poll': None if blocked else gen_poll_dict(p.id, name),
'author_title': p.author_title
} }
if is_admin(name): if is_admin(name):
r['hot_score'] = p.hot_score r['hot_score'] = p.hot_score
@ -134,6 +137,7 @@ def map_comment(p, name):
'blocked': (blocked := is_blocked(c.name_hash, name)), 'blocked': (blocked := is_blocked(c.name_hash, name)),
'cid': c.id, 'cid': c.id,
'name_id': gen_name_id(c.name_hash), 'name_id': gen_name_id(c.name_hash),
'author_title': c.author_title,
'pid': p.id, 'pid': p.id,
'text': '' if blocked else c.content, 'text': '' if blocked else c.content,
'timestamp': c.timestamp, 'timestamp': c.timestamp,

Loading…
Cancel
Save