from flask import Flask, request, render_template, send_from_directory, abort, redirect, session
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from flask_limiter import Limiter
|
|
from flask_limiter.util import get_remote_address
|
|
import re
|
|
import random
|
|
from datetime import datetime
|
|
from dateutil.tz import tzlocal
|
|
import html2text
|
|
from config_fudan import C
|
|
|
|
app = Flask(__name__)
|
|
app.config.from_object('config_fudan.C')
|
|
app.secret_key = C.session_key
|
|
|
|
limiter = Limiter(
|
|
app,
|
|
key_func=get_remote_address,
|
|
default_limits=["50 / minute"],
|
|
)
|
|
|
|
db = SQLAlchemy(app)
|
|
|
|
class Candidate(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
content = db.Column(db.String(4000))
|
|
private = db.Column(db.String(1000))
|
|
time = db.Column(db.DateTime)
|
|
likeNum = db.Column(db.Integer, default=0)
|
|
|
|
# always increment 1 for the id of a new record
|
|
__table_args__ = { 'sqlite_autoincrement': True }
|
|
|
|
class Like(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
cid = db.Column(db.Integer) # (member) id of class Candidate
|
|
uid = db.Column(db.Integer) # id of user
|
|
|
|
db.create_all()
|
|
|
|
@app.route('/img/<path:path>')
|
|
def send_img(path):
|
|
return send_from_directory('static/img', path)
|
|
|
|
@app.route('/ordinary/set_session')
|
|
@limiter.limit("2 / hour; 1 / 5 minute")
|
|
def set_session():
|
|
if 'uid' not in session:
|
|
session['uid'] = random.randint(0, 2000000000)
|
|
session.permanent = True
|
|
return redirect('.')
|
|
|
|
@app.route('/ordinary/')
|
|
def can_list():
|
|
key = request.args.get('key')
|
|
sort_by = request.args.get('sort_by', 'time')
|
|
|
|
if 'uid' not in session:
|
|
return redirect('set_session')
|
|
uid = session['uid']
|
|
|
|
q = Candidate.query
|
|
q = q.order_by(db.desc('likeNum')) if sort_by=='likeNum' else q.order_by(db.desc('id'))
|
|
pag = q.paginate(max_per_page=100)
|
|
|
|
def check_like(c):
|
|
c.liked = 'liked' if Like.query.filter_by(uid=uid, cid=c.id).count() else 'like'
|
|
return c
|
|
|
|
pag.items = map(check_like, pag.items)
|
|
|
|
vs = [{
|
|
'name': name,
|
|
'ques': ques,
|
|
'hint': hint
|
|
} for name, ques, hint, ans in C.verify
|
|
]
|
|
|
|
return render_template('list.html', pagination=pag, vs=vs, showPrivate=(key==C.key), sort_by=sort_by, key=key, text1=C.text1, text2=C.text2)
|
|
|
|
@app.route('/ordinary/new', methods=['POST'])
|
|
@limiter.limit("5 / hour; 1 / 2 second")
|
|
def new_one():
|
|
|
|
content = request.form.get('text')
|
|
private = request.form.get('privateText')
|
|
|
|
for name, ques, hint, ans in C.verify:
|
|
if request.form.get(name) != ans:
|
|
return '''<html>
|
|
<head>
|
|
<meta charset='UTF-8'>
|
|
<meta name='viewport' content='width=device-width initial-scale=1'>
|
|
<title>错误</title>
|
|
</head>
|
|
<body>
|
|
<h1>验证问题回答错误</h1>
|
|
<a href="##" onclick="window.history.back()">回退</a>
|
|
</body>
|
|
</html>
|
|
''', 401
|
|
|
|
if not content or len(content)>4000: abort(422)
|
|
if private and len(private)>1000: abort(422)
|
|
|
|
if not Candidate.query.filter_by(content=content).first():
|
|
c = Candidate(
|
|
content=content,
|
|
private=private,
|
|
time=datetime.now()
|
|
)
|
|
db.session.add(c)
|
|
db.session.commit()
|
|
|
|
return redirect(".")
|
|
|
|
@limiter.limit("100 / hour")
|
|
@app.route('/ordinary/<int:id>/like', methods=['POST'])
|
|
def like(id):
|
|
c = Candidate.query.get(id)
|
|
if not c:
|
|
abort(404)
|
|
|
|
uid = session['uid']
|
|
if not uid: abort(401)
|
|
if Like.query.filter_by(uid=uid, cid=id).first():
|
|
return '点赞过了', 403
|
|
|
|
l = Like(uid=uid, cid=id)
|
|
c.likeNum += 1
|
|
db.session.add(l)
|
|
db.session.commit()
|
|
|
|
return str(c.likeNum)
|
|
|
|
@app.route('/ordinary/<int:id>/delete', methods=['POST'])
|
|
def delete(id):
|
|
key = request.form.get('key')
|
|
if key != C.key:
|
|
abort(401)
|
|
|
|
c = Candidate.query.get(id)
|
|
if not c:
|
|
abort(404)
|
|
|
|
db.session.delete(c)
|
|
db.session.commit()
|
|
|
|
return redirect('..')
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True)
|
|
|