commit 02e30d3eb9f946abcbc08d1a64b168e6fb07ab41 Author: Ben Kurtovic Date: Sun Feb 7 02:22:16 2016 -0600 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3e5d880 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016 Ben Kurtovic + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..da9ed3f --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +This is a tool that calculates the +[Template Influence Factor](https://en.wikipedia.org/wiki/User:The_Earwig/Sandbox/TIF) +of a [Wikipedia template](https://en.wikipedia.org/wiki/Help:Template), which +is a measure of how +[high risk](https://en.wikipedia.org/wiki/Wikipedia:High-risk_templates) it is, +for the purposes of anti-vandalism. It runs on +[Wikimedia Labs](https://tools.wmflabs.org/earwig-dev/tif). + +Dependencies +============ + +* [earwigbot](https://github.com/earwig/earwigbot) >= 0.2 +* [flask](http://flask.pocoo.org/) >= 0.10.1 +* [flask-mako](https://pythonhosted.org/Flask-Mako/) >= 0.3 +* [mako](http://www.makotemplates.org/) >= 1.0.3 +* [oursql](http://packages.python.org/oursql/) >= 0.9.3.1 + +Running +======= + +- Install all dependencies listed above. + +- Create an SQL database ... + +- Create an earwigbot instance in `.earwigbot` (run `earwigbot .earwigbot`). In + `.earwigbot/config.yml`, fill out the connection info for the database by + adding the following to the `wiki` section: + + _tifSQL: + host: + db: + + If additional arguments are needed by `oursql.connect()`, like usernames or + passwords, they should be added to the `_tifSQL` section. + +- Start the web server (on Tool Labs, `webservice2 uwsgi-python start`). diff --git a/app.py b/app.py new file mode 100644 index 0000000..db8c411 --- /dev/null +++ b/app.py @@ -0,0 +1,28 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +from flask import Flask, g +from flask.ext.mako import MakoTemplates, render_template + +from tif.util import catch_errors, set_up_hash_caching + +app = Flask(__name__) +MakoTemplates(app) +set_up_hash_caching(app) + +@app.before_request +def prepare_request(): + g._db = None + +@app.teardown_appcontext +def close_databases(error): + if g._db: + g._db.close() + +@app.route("/") +@catch_errors(app) +def index(): + return render_template("index.mako") + +if __name__ == '__main__': + app.run() diff --git a/templates/error.mako b/templates/error.mako new file mode 100644 index 0000000..e69de29 diff --git a/templates/index.mako b/templates/index.mako new file mode 100644 index 0000000..e69de29 diff --git a/tif/__init__.py b/tif/__init__.py new file mode 100644 index 0000000..89907bf --- /dev/null +++ b/tif/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/tif/util.py b/tif/util.py new file mode 100644 index 0000000..c699e1d --- /dev/null +++ b/tif/util.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +from functools import wraps +from hashlib import md5 +from os import path +from traceback import format_exc + +from flask.ext.mako import render_template, TemplateError + +__all__ = ["catch_errors", "set_up_hash_caching"] + +def catch_errors(app): + def callback(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 + return callback + +def set_up_hash_caching(app): + def callback(app, 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._hash_cache = {} + app.url_build_error_handlers.append(lambda *args: callback(app, *args))