|
- #! /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()
|