重构
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import random
|
||||
import string
|
||||
import time
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///hole.db'
|
||||
@@ -9,7 +7,6 @@ CLIENT_ID = '<id>'
|
||||
CLIENT_SECRET = '<secret>'
|
||||
MASTODON_URL = 'https://mastodon.social'
|
||||
REDIRECT_URI = 'http://hole.thu.monster/_auth'
|
||||
SALT = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
|
||||
ADMINS = ['cs_114514']
|
||||
START_TIME = int(time.time())
|
||||
ENABLE_TMP = True
|
||||
|
||||
108
hole.py
108
hole.py
@@ -10,12 +10,15 @@ from sqlalchemy.sql.expression import func
|
||||
|
||||
from mastodon import Mastodon
|
||||
from models import db, User, Post, Comment, Attention, TagRecord, Syslog
|
||||
from utils import get_current_user, map_post, map_comment, map_syslog, check_attention, hash_name, look, get_num, tmp_token, is_admin
|
||||
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
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hole.db'
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.config['JSON_AS_ASCII'] = False
|
||||
app.config['SALT'] = ''.join(random.choices(
|
||||
string.ascii_letters + string.digits, k=32
|
||||
))
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
db.init_app(app)
|
||||
@@ -86,7 +89,7 @@ def auth():
|
||||
|
||||
@app.route('/_api/v1/getlist')
|
||||
def get_list():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
p = request.args.get('p', type=int, default=1)
|
||||
order_mode = request.args.get('order_mode', type=int, default=0)
|
||||
@@ -111,7 +114,7 @@ def get_list():
|
||||
|
||||
posts = query.order_by(order).paginate(p, PER_PAGE)
|
||||
|
||||
data = list(map(map_post, posts.items, [u.name] * len(posts.items)))
|
||||
data = list(map(map_post, posts.items, [username] * len(posts.items)))
|
||||
|
||||
return {
|
||||
'code': 0,
|
||||
@@ -123,15 +126,17 @@ def get_list():
|
||||
|
||||
@app.route('/_api/v1/getone')
|
||||
def get_one():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
pid = request.args.get('pid', type=int)
|
||||
|
||||
post = Post.query.get_or_404(pid)
|
||||
if post.deleted or post.is_reported:
|
||||
if post.deleted or post.is_reported and not (
|
||||
check_can_del(username, post.name_hash)
|
||||
):
|
||||
abort(451)
|
||||
|
||||
data = map_post(post, u.name)
|
||||
data = map_post(post, username)
|
||||
|
||||
return {
|
||||
'code': 0,
|
||||
@@ -141,7 +146,7 @@ def get_one():
|
||||
|
||||
@app.route('/_api/v1/search')
|
||||
def search():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
page = request.args.get('page', type=int, default=1)
|
||||
pagesize = min(request.args.get('pagesize', type=int, default=200), 200)
|
||||
@@ -155,7 +160,8 @@ def search():
|
||||
tag=keywords
|
||||
).all()
|
||||
|
||||
tag_pids = [tag_pid for tag_pid, in tag_pids] or [0] # sql not allowed empty in
|
||||
tag_pids = [
|
||||
tag_pid for tag_pid, in tag_pids] or [0] # sql not allowed empty in
|
||||
|
||||
posts = Post.query.filter(
|
||||
Post.search_text.like("%{}%".format(keywords))
|
||||
@@ -177,7 +183,7 @@ def search():
|
||||
).all() + posts
|
||||
|
||||
data = [
|
||||
map_post(post, u.name)
|
||||
map_post(post, username)
|
||||
for post in posts
|
||||
]
|
||||
|
||||
@@ -191,27 +197,23 @@ def search():
|
||||
@app.route('/_api/v1/dopost', methods=['POST'])
|
||||
@limiter.limit("50 / hour; 1 / 3 second")
|
||||
def do_post():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
allow_search = request.form.get('allow_search')
|
||||
print(allow_search)
|
||||
content = request.form.get('text')
|
||||
content = content.strip() if content else None
|
||||
content = '[tmp]\n' + content if u.name[:4] == 'tmp_' else content
|
||||
content = request.form.get('text', '').strip()
|
||||
content = ('[tmp]\n' if username[:4] == 'tmp_' else '') + content
|
||||
post_type = request.form.get('type')
|
||||
cw = request.form.get('cw')
|
||||
cw = cw.strip() if cw else None
|
||||
cw = request.form.get('cw', '').strip()
|
||||
|
||||
if not content or len(content) > 4096:
|
||||
abort(422)
|
||||
if cw and len(cw) > 32:
|
||||
if not content or len(content) > 4096 or len(cw) > 32:
|
||||
abort(422)
|
||||
|
||||
search_text = content.replace(
|
||||
'\n', '') if allow_search else ''
|
||||
|
||||
p = Post(
|
||||
name_hash=hash_name(u.name),
|
||||
name_hash=hash_name(username),
|
||||
content=content,
|
||||
search_text=search_text,
|
||||
post_type=post_type,
|
||||
@@ -238,7 +240,7 @@ def do_post():
|
||||
if not re.match('\\d+', tag):
|
||||
db.session.add(TagRecord(tag=tag, pid=p.id))
|
||||
|
||||
db.session.add(Attention(name_hash=hash_name(u.name), pid=p.id))
|
||||
db.session.add(Attention(name_hash=hash_name(username), pid=p.id))
|
||||
db.session.commit()
|
||||
|
||||
return {
|
||||
@@ -250,7 +252,7 @@ def do_post():
|
||||
@app.route('/_api/v1/editcw', methods=['POST'])
|
||||
@limiter.limit("50 / hour; 1 / 2 second")
|
||||
def edit_cw():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
cw = request.form.get('cw')
|
||||
pid = get_num(request.form.get('pid'))
|
||||
@@ -260,11 +262,8 @@ def edit_cw():
|
||||
abort(422)
|
||||
|
||||
post = Post.query.get_or_404(pid)
|
||||
if post.deleted:
|
||||
abort(451)
|
||||
|
||||
if not (u.name in app.config.get('ADMINS')
|
||||
or hash_name(u.name) == post.name_hash):
|
||||
if not check_can_del(username, post.name_hash):
|
||||
abort(403)
|
||||
|
||||
post.cw = cw
|
||||
@@ -275,21 +274,19 @@ def edit_cw():
|
||||
|
||||
@app.route('/_api/v1/getcomment')
|
||||
def get_comment():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
pid = get_num(request.args.get('pid'))
|
||||
|
||||
post = Post.query.get(pid)
|
||||
if not post:
|
||||
abort(404)
|
||||
if post.deleted:
|
||||
post = Post.query.get_or_404(pid)
|
||||
if post.deleted and not check_can_del(username, post.name_hash):
|
||||
abort(451)
|
||||
|
||||
data = map_comment(post, u.name)
|
||||
data = map_comment(post, username)
|
||||
|
||||
return {
|
||||
'code': 0,
|
||||
'attention': check_attention(u.name, pid),
|
||||
'attention': check_attention(username, pid),
|
||||
'likenum': post.likenum,
|
||||
'data': data
|
||||
}
|
||||
@@ -298,24 +295,24 @@ def get_comment():
|
||||
@app.route('/_api/v1/docomment', methods=['POST'])
|
||||
@limiter.limit("50 / hour; 1 / 3 second")
|
||||
def do_comment():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
pid = get_num(request.form.get('pid'))
|
||||
|
||||
post = Post.query.get(pid)
|
||||
if not post:
|
||||
abort(404)
|
||||
if post.deleted:
|
||||
if post.deleted and not check_can_del(username, post.name_hash):
|
||||
abort(451)
|
||||
|
||||
content = request.form.get('text')
|
||||
content = content.strip() if content else None
|
||||
content = '[tmp]\n' + content if u.name[:4] == 'tmp_' else content
|
||||
content = '[tmp]\n' + content if username[:4] == 'tmp_' else content
|
||||
if not content or len(content) > 4096:
|
||||
abort(422)
|
||||
|
||||
c = Comment(
|
||||
name_hash=hash_name(u.name),
|
||||
name_hash=hash_name(username),
|
||||
content=content,
|
||||
)
|
||||
post.comments.append(c)
|
||||
@@ -325,11 +322,11 @@ def do_comment():
|
||||
post.hot_score += 1
|
||||
|
||||
at = Attention.query.filter_by(
|
||||
name_hash=hash_name(u.name), pid=pid
|
||||
name_hash=hash_name(username), pid=pid
|
||||
).first()
|
||||
|
||||
if not at:
|
||||
at = Attention(name_hash=hash_name(u.name), pid=pid, disabled=False)
|
||||
at = Attention(name_hash=hash_name(username), pid=pid, disabled=False)
|
||||
db.session.add(at)
|
||||
post.likenum += 1
|
||||
if post.hot_score != -1:
|
||||
@@ -350,8 +347,8 @@ def do_comment():
|
||||
@app.route('/_api/v1/attention', methods=['POST'])
|
||||
@limiter.limit("200 / hour; 1 / second")
|
||||
def attention():
|
||||
u = get_current_user()
|
||||
if u.name[:4] == 'tmp_':
|
||||
username = get_current_username()
|
||||
if username[:4] == 'tmp_':
|
||||
abort(403)
|
||||
|
||||
s = request.form.get('switch')
|
||||
@@ -365,11 +362,11 @@ def attention():
|
||||
abort(404)
|
||||
|
||||
at = Attention.query.filter_by(
|
||||
name_hash=hash_name(u.name), pid=pid
|
||||
name_hash=hash_name(username), pid=pid
|
||||
).first()
|
||||
|
||||
if not at:
|
||||
at = Attention(name_hash=hash_name(u.name), pid=pid, disabled=True)
|
||||
at = Attention(name_hash=hash_name(username), pid=pid, disabled=True)
|
||||
db.session.add(at)
|
||||
if post.hot_score != -1:
|
||||
post.hot_score += 2
|
||||
@@ -389,12 +386,12 @@ def attention():
|
||||
|
||||
@app.route('/_api/v1/getattention')
|
||||
def get_attention():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
ats = Attention.query.with_entities(
|
||||
Attention.pid
|
||||
).filter_by(
|
||||
name_hash=hash_name(u.name), disabled=False
|
||||
name_hash=hash_name(username), disabled=False
|
||||
).all()
|
||||
|
||||
pids = [pid for pid, in ats] or [0] # sql not allow empty in
|
||||
@@ -405,7 +402,7 @@ def get_attention():
|
||||
).order_by(Post.id.desc()).all()
|
||||
|
||||
data = [
|
||||
map_post(post, u.name, 10)
|
||||
map_post(post, username, 10)
|
||||
for post in posts
|
||||
]
|
||||
|
||||
@@ -419,7 +416,7 @@ def get_attention():
|
||||
@app.route('/_api/v1/delete', methods=['POST'])
|
||||
@limiter.limit("50 / hour; 1 / 3 second")
|
||||
def delete():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
obj_type = request.form.get('type')
|
||||
obj_id = get_num(request.form.get('id'))
|
||||
@@ -436,7 +433,7 @@ def delete():
|
||||
if not obj:
|
||||
abort(404)
|
||||
|
||||
if obj.name_hash == hash_name(u.name):
|
||||
if obj.name_hash == hash_name(username):
|
||||
if obj_type == 'pid':
|
||||
if len(obj.comments):
|
||||
abort(403)
|
||||
@@ -445,12 +442,12 @@ def delete():
|
||||
db.session.delete(obj)
|
||||
else:
|
||||
obj.deleted = True
|
||||
elif u.name in app.config.get('ADMINS'):
|
||||
elif username in app.config.get('ADMINS'):
|
||||
obj.deleted = True
|
||||
db.session.add(Syslog(
|
||||
log_type='ADMIN DELETE',
|
||||
log_detail=f"{obj_type}={obj_id}\n{note}",
|
||||
name_hash=hash_name(u.name)
|
||||
name_hash=hash_name(username)
|
||||
))
|
||||
if note.startswith('!ban'):
|
||||
db.session.add(Syslog(
|
||||
@@ -467,7 +464,7 @@ def delete():
|
||||
|
||||
@app.route('/_api/v1/systemlog')
|
||||
def system_log():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
ss = Syslog.query.order_by(db.desc('timestamp')).limit(100).all()
|
||||
|
||||
@@ -475,14 +472,14 @@ def system_log():
|
||||
'start_time': app.config['START_TIME'],
|
||||
'salt': look(app.config['SALT']),
|
||||
'tmp_token': tmp_token(),
|
||||
'data': [map_syslog(s, u) for s in ss]
|
||||
'data': [map_syslog(s, username) for s in ss]
|
||||
}
|
||||
|
||||
|
||||
@app.route('/_api/v1/report', methods=['POST'])
|
||||
@limiter.limit("10 / hour; 1 / 3 second")
|
||||
def report():
|
||||
u = get_current_user()
|
||||
username = get_current_username()
|
||||
|
||||
pid = get_num(request.form.get('pid'))
|
||||
|
||||
@@ -491,7 +488,7 @@ def report():
|
||||
db.session.add(Syslog(
|
||||
log_type='REPORT',
|
||||
log_detail=f"pid={pid}\n{reason}",
|
||||
name_hash=hash_name(u.name)
|
||||
name_hash=hash_name(username)
|
||||
))
|
||||
|
||||
post = Post.query.get(pid)
|
||||
@@ -505,9 +502,8 @@ def report():
|
||||
|
||||
@app.route('/_api/v1/update_score', methods=['POST'])
|
||||
def edit_hot_score():
|
||||
u = get_current_user()
|
||||
if not is_admin(u.name):
|
||||
print(u.name)
|
||||
username = get_current_username()
|
||||
if not is_admin(username):
|
||||
abort(403)
|
||||
|
||||
pid = request.form.get('pid', type=int)
|
||||
|
||||
@@ -26,7 +26,8 @@ class Post(db.Model):
|
||||
deleted = db.Column(db.Boolean, default=False)
|
||||
is_reported = db.Column(db.Boolean, default=False)
|
||||
comment_timestamp = db.Column(db.Integer, default=0, index=True)
|
||||
hot_score = db.Column(db.Integer, default=0, nullable=False, server_default="0")
|
||||
hot_score = db.Column(db.Integer, default=0,
|
||||
nullable=False, server_default="0")
|
||||
|
||||
comments = db.relationship('Comment', backref='post', lazy=True)
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
Flask>=1.1.2
|
||||
Flask-Limit>=1.0.2
|
||||
Flask-Limiter>=1.3.1
|
||||
Flask-Login>=0.5.0
|
||||
Flask-Migrate>=2.5.3
|
||||
Flask-SQLAlchemy>=2.4.4
|
||||
Mastodon.py>=1.5.1
|
||||
Flask
|
||||
Flask-Limit
|
||||
Flask-Limiter
|
||||
Flask-Login
|
||||
Flask-Migrate
|
||||
Flask-SQLAlchemy
|
||||
Mastodon.py
|
||||
redis
|
||||
|
||||
21
utils.py
21
utils.py
@@ -2,6 +2,7 @@ import hashlib
|
||||
import time
|
||||
from flask import request, abort, current_app
|
||||
from models import User, Attention, Syslog
|
||||
from config import ADMINS, ENABLE_TMP
|
||||
|
||||
|
||||
def get_config(key):
|
||||
@@ -9,7 +10,7 @@ def get_config(key):
|
||||
|
||||
|
||||
def is_admin(name):
|
||||
return name in get_config('ADMINS')
|
||||
return name in ADMINS
|
||||
|
||||
|
||||
def tmp_token():
|
||||
@@ -18,27 +19,29 @@ def tmp_token():
|
||||
)[5:21]
|
||||
|
||||
|
||||
def get_current_user():
|
||||
def get_current_username():
|
||||
token = request.headers.get('User-Token') or request.args.get('user_token')
|
||||
if not token:
|
||||
abort(401)
|
||||
|
||||
if len(token.split('_')) == 2 and get_config('ENABLE_TMP'):
|
||||
if len(token.split('_')) == 2 and ENABLE_TMP:
|
||||
tt, suf = token.split('_')
|
||||
if tt != tmp_token():
|
||||
abort(401)
|
||||
return User(name='tmp_' + suf)
|
||||
return 'tmp_' + suf
|
||||
|
||||
u = User.query.filter_by(token=token).first()
|
||||
if not u or Syslog.query.filter_by(
|
||||
log_type='BANNED', name_hash=hash_name(u.name)).first():
|
||||
abort(401)
|
||||
return u
|
||||
return u.name
|
||||
|
||||
|
||||
def hash_name(name):
|
||||
print(name)
|
||||
return hashlib.sha256(
|
||||
(get_config('SALT') + name).encode('utf-8')).hexdigest()
|
||||
(get_config('SALT') + name).encode('utf-8')
|
||||
).hexdigest()
|
||||
|
||||
|
||||
def map_post(p, name, mc=50):
|
||||
@@ -81,10 +84,10 @@ def map_comment(p, name):
|
||||
]
|
||||
|
||||
|
||||
def map_syslog(s, u=None):
|
||||
def map_syslog(s, username):
|
||||
return {
|
||||
'type': s.log_type,
|
||||
'detail': s.log_detail if check_can_del(u.name, s.name_hash) else '',
|
||||
'detail': s.log_detail if check_can_del(username, s.name_hash) else '',
|
||||
'user': look(s.name_hash),
|
||||
'timestamp': s.timestamp
|
||||
}
|
||||
@@ -99,7 +102,7 @@ def check_attention(name, pid):
|
||||
|
||||
|
||||
def check_can_del(name, author_hash):
|
||||
return int(hash_name(name) == author_hash or is_admin(name))
|
||||
return hash_name(name) == author_hash or is_admin(name)
|
||||
|
||||
|
||||
def look(s):
|
||||
|
||||
Reference in New Issue
Block a user