-
Notifications
You must be signed in to change notification settings - Fork 9
/
app.py
executable file
·197 lines (172 loc) · 6.26 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from functools import wraps
from hashlib import md5
from json import dumps
from logging import DEBUG, INFO, getLogger
from logging.handlers import TimedRotatingFileHandler
from multiprocessing import Value
from os import path
from time import asctime
from traceback import format_exc
from urllib import quote_plus, quote
from earwigbot.bot import Bot
from earwigbot.wiki.copyvios import globalize
from flask import Flask, g, make_response, request, redirect, session
from flask_mako import MakoTemplates, render_template, TemplateError
from copyvios.api import format_api_error, handle_api_request
from copyvios.checker import do_check
from copyvios.cookies import parse_cookies
from copyvios.misc import cache, get_notice
from copyvios.settings import process_settings
from copyvios.sites import update_sites
from copyvios.auth import oauth_login_start, oauth_login_end, clear_login_session
app = Flask(__name__)
MakoTemplates(app)
hand = TimedRotatingFileHandler("logs/app.log", when="midnight", backupCount=7)
hand.setLevel(DEBUG)
app.config.from_pyfile("config.py", True)
app.logger.addHandler(hand)
app.logger.info(u"Flask server started " + asctime())
app._hash_cache = {}
def catch_errors(func):
@wraps(func)
def inner(*args, **kwargs):
try:
return func(*args, **kwargs)
except TemplateError as exc:
app.logger.error(u"Caught exception:\n{0}".format(exc.text))
return render_template("error.mako", traceback=exc.text)
except Exception:
app.logger.exception(u"Caught exception:")
return render_template("error.mako", traceback=format_exc())
return inner
@app.before_first_request
def setup_app():
cache.bot = Bot(".earwigbot", 100)
cache.langs, cache.projects = [], []
cache.last_sites_update = 0
cache.background_data = {}
cache.last_background_updates = {}
oauth_config = cache.bot.config.wiki.get('copyvios', {}).get('oauth', {})
if oauth_config.get('consumer_token') is None:
raise ValueError("No OAuth consumer token is configured (config.wiki.copyvios.oauth.consumer_token).")
if oauth_config.get('consumer_secret') is None:
raise ValueError("No OAuth consumer secret is configured (config.wiki.copyvios.oauth.consumer_secret).")
globalize(num_workers=8)
@app.before_request
def prepare_request():
g._db = None
g.cookies = parse_cookies(
request.script_root or "/", request.environ.get("HTTP_COOKIE"))
g.new_cookies = []
@app.after_request
def add_new_cookies(response):
for cookie in g.new_cookies:
response.headers.add("Set-Cookie", cookie)
return response
@app.after_request
def write_access_log(response):
msg = u"%s %s %s %s -> %s"
app.logger.debug(msg, asctime(), request.method, request.path,
request.values.to_dict(), response.status_code)
return response
@app.teardown_appcontext
def close_databases(error):
if g._db:
g._db.close()
def external_url_handler(error, endpoint, values):
if endpoint == "static" and "file" in values:
fpath = path.join(app.static_folder, values["file"])
mtime = path.getmtime(fpath)
cache = app._hash_cache.get(fpath)
if cache and cache[0] == mtime:
hashstr = cache[1]
else:
with open(fpath, "rb") as f:
hashstr = md5(f.read()).hexdigest()
app._hash_cache[fpath] = (mtime, hashstr)
return "/static/{0}?v={1}".format(values["file"], hashstr)
raise error
app.url_build_error_handlers.append(external_url_handler)
@app.route("/")
@catch_errors
def index():
notice = get_notice()
update_sites()
query = do_check()
if query.submitted and query.error == "not logged in":
return redirect("/login?next=" + quote("/?" + request.query_string), 302)
return render_template(
"index.mako", notice=notice, query=query, result=query.result,
turnitin_result=query.turnitin_result)
@app.route("/login", methods=["GET", "POST"])
@catch_errors
def login():
try:
redirect_url = oauth_login_start() if request.method == "POST" else None
if redirect_url:
return redirect(redirect_url, 302)
except Exception as e:
app.log_exception(e)
print e.message
kwargs = {"error": e.message}
else:
if session.get("username") is not None:
return redirect("/", 302)
kwargs = {"error": request.args.get("error")}
return render_template("login.mako", **kwargs)
@app.route("/logout", methods=["GET", "POST"])
@catch_errors
def logout():
if request.method == "POST":
clear_login_session()
return redirect("/", 302)
else:
return render_template("logout.mako")
@app.route("/oauth-callback")
@catch_errors
def oauth_callback():
try:
next_url = oauth_login_end()
except Exception as e:
app.log_exception(e)
return redirect("/login?error=" + quote_plus(e.message), 302)
else:
return redirect(next_url, 302)
@app.route("/settings", methods=["GET", "POST"])
@catch_errors
def settings():
status = process_settings() if request.method == "POST" else None
update_sites()
default = cache.bot.wiki.get_site()
kwargs = {"status": status, "default_lang": default.lang,
"default_project": default.project}
return render_template("settings.mako", **kwargs)
@app.route("/api")
@catch_errors
def api():
return render_template("api.mako", help=True)
@app.route("/api.json")
@catch_errors
def api_json():
if not request.args:
return render_template("api.mako", help=True)
format = request.args.get("format", "json")
if format in ["json", "jsonfm"]:
update_sites()
try:
result = handle_api_request()
except Exception as exc:
result = format_api_error("unhandled_exception", exc)
else:
errmsg = u"Unknown format: '{0}'".format(format)
result = format_api_error("unknown_format", errmsg)
if format == "jsonfm":
return render_template("api.mako", help=False, result=result)
resp = make_response(dumps(result))
resp.mimetype = "application/json"
resp.headers["Access-Control-Allow-Origin"] = "*"
return resp
if __name__ == '__main__':
app.run()