You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
5.0 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. from flask import Flask, request, render_template, send_from_directory, abort, redirect, session, url_for
  2. from flask_sqlalchemy import SQLAlchemy
  3. from flask_limiter import Limiter
  4. from flask_limiter.util import get_remote_address
  5. import ipfshttpclient
  6. from datetime import date, datetime
  7. from functools import wraps
  8. import hashlib
  9. import random
  10. import os
  11. from config import C
  12. app = Flask(__name__)
  13. app.config.from_object('config.C')
  14. app.secret_key = C.session_key
  15. limiter = Limiter(
  16. app,
  17. key_func=get_remote_address,
  18. default_limits=["50 / minute"],
  19. )
  20. db = SQLAlchemy(app)
  21. ipfs_client = ipfshttpclient.connect()
  22. class Paper(db.Model):
  23. id = db.Column(db.Integer, primary_key=True)
  24. course = db.Column(db.String(30), index=True)
  25. teacher = db.Column(db.String(30), index=True)
  26. year = db.Column(db.Integer, index=True)
  27. author = db.Column(db.String(30), index=True)
  28. notes = db.Column(db.String(200))
  29. anon = db.Column(db.Boolean)
  30. create_date = db.Column(db.Date)
  31. like_num = db.Column(db.Integer, index=True, default=0)
  32. down_num = db.Column(db.Integer, index=True, default=0)
  33. file_hash = db.Column(db.String(64))
  34. if __name__ == "__main__":
  35. db.create_all()
  36. def login_required(allow_guest=True):
  37. def login_required_instance(f):
  38. @wraps(f)
  39. def df(*args, **kwargs):
  40. username = session.get('username')
  41. if not username or (not allow_guest and username.startswith('guest~')):
  42. return redirect(url_for('login'))
  43. return f(*args, **kwargs, username=username)
  44. return df
  45. return login_required_instance
  46. @app.route('/pastExam/login/')
  47. def login():
  48. return app.send_static_file('login/index.html')
  49. @app.route('/pastExam/login/guest/')
  50. def guest_login():
  51. return render_template('guest-login.html', vs=C.verify, allow_guest_upload=C.allow_guest_upload)
  52. @app.route('/pastExam/login/guest/verify', methods=['POST'])
  53. @limiter.limit("10 / hour")
  54. def guest_login_send():
  55. for name, ques, hint, ans in C.verify:
  56. if request.form.get(name) != ans:
  57. return '错误!', 401
  58. if 'uid' not in session:
  59. session['uid'] = random.randint(0, 10000000)
  60. session['username'] = 'guest~%s' % session['uid']
  61. session.permanent = True
  62. return {'r':0}
  63. @app.route('/pastExam/')
  64. @login_required()
  65. def list(username):
  66. course = request.args.get('course')
  67. teacher = request.args.get('teacher')
  68. year = request.args.get('year')
  69. year = year and year.isdigit() and int(year)
  70. has_course = course is not None
  71. has_teacher = teacher is not None
  72. has_year = year is not None
  73. ept = not (has_course or has_teacher or has_year) and 'page' not in request.args
  74. ps = Paper.query
  75. if course:
  76. ps = ps.filter_by(course=course)
  77. if teacher:
  78. ps = ps.filter_by(teacher=teacher)
  79. if year or year==0:
  80. ps = ps.filter_by(year=year)
  81. ps = ps.order_by(db.desc('like_num'))
  82. pagination = ps.paginate(max_per_page=100)
  83. curr_year = date.today().year
  84. all_courses = [i for i, in db.session.query(Paper.course.distinct()).all()]
  85. all_teachers = [i for i, in db.session.query(Paper.teacher.distinct()).all()]
  86. all_years = [i for i, in db.session.query(Paper.year.distinct()).all()]
  87. ipfs_version = hashlib.sha256(C.ipfs_base_url.encode('utf-8')).hexdigest()
  88. return render_template('list.html', **locals())
  89. def check_length(x, limit=30, allow_null=False):
  90. return (x and len(x) <= limit) or (allow_null and not x)
  91. @app.route('/pastExam/upload', methods=['POST'])
  92. @limiter.limit("10 / hour")
  93. @login_required(allow_guest=C.allow_guest_upload)
  94. def upload(username):
  95. name = request.form.get('name')
  96. teacher = request.form.get('teacher')
  97. year = request.form.get('year')
  98. year = year and year.isdigit() and int(year) or 0
  99. notes = request.form.get('notes', '')
  100. anon = request.form.get('anon') == 'on'
  101. if not (check_length(name) and check_length(teacher) and check_length(notes, 200, True)):
  102. abort(422)
  103. files = request.files.getlist('files[]')
  104. dir_name = username + str(datetime.now())
  105. base_path = os.path.join('/tmp', dir_name)
  106. os.mkdir(base_path)
  107. for f in files:
  108. filename = f.filename.replace('/','_')
  109. f.save(os.path.join(base_path, filename))
  110. res = ipfs_client.add(base_path)
  111. file_hash = ''
  112. for r in res:
  113. if r.get('Name') == dir_name:
  114. file_hash = r.get('Hash')
  115. if not file_hash:
  116. abort(500)
  117. paper = Paper(
  118. course=name,
  119. teacher=teacher,
  120. year=year,
  121. notes=notes,
  122. anon=anon,
  123. author=username,
  124. create_date=date.today(),
  125. file_hash=file_hash
  126. )
  127. db.session.add(paper)
  128. db.session.commit()
  129. return redirect('.#part2')
  130. @app.route('/pastExam/<pid>/download')
  131. @login_required()
  132. def download(pid, username):
  133. p = Paper.query.get_or_404(pid)
  134. # TODO: download number
  135. return redirect(C.ipfs_base_url + p.file_hash, code=301) # 301减少不必要的请求
  136. # TODO like