@@ -5,7 +5,7 @@ from time import asctime | |||
from logging import DEBUG | |||
from logging.handlers import TimedRotatingFileHandler | |||
from flask import Flask, request | |||
from flask import Flask, g, request | |||
from flask.ext.mako import MakoTemplates, render_template | |||
from flup.server.fcgi import WSGIServer | |||
@@ -15,10 +15,24 @@ app = Flask(__name__) | |||
MakoTemplates(app) | |||
app.logger.setLevel(DEBUG) | |||
app.logger.addHandler(TimedRotatingFileHandler("logs/app.log", when="D", | |||
interval=1, backupCount=7)) | |||
app.logger.addHandler(TimedRotatingFileHandler( | |||
"logs/app.log", when="D", interval=1, backupCount=7)) | |||
app.logger.info(u"Flask server started " + asctime()) | |||
@app.before_request | |||
def prepare_cookies(): | |||
cookie_string = request.environ.get("HTTP_COOKIE") | |||
g.cookies = parse_cookies(request.script_root, cookie_string) | |||
g.new_cookies = [] | |||
@app.after_request | |||
def add_new_cookies(response): | |||
if g.new_cookies: | |||
if "Set-Cookie" in response.headers: | |||
g.new_cookies.insert(0, response.headers["Set-Cookie"]) | |||
response.headers["Set-Cookie"] = "; ".join(g.new_cookies) | |||
return response | |||
@app.after_request | |||
def write_access_log(response): | |||
msg = u"%s %s -> %s" | |||
@@ -27,21 +41,15 @@ def write_access_log(response): | |||
@app.route("/") | |||
def index(): | |||
root = request.environ["SCRIPT_NAME"] | |||
cookies = parse_cookies(root, request.environ.get("HTTP_COOKIE")) | |||
return render_template("index.mako", root=root, environ=request.environ, cookies=cookies) | |||
return render_template("index.mako") | |||
@app.route("/settings", methods=["GET", "POST"]) | |||
def settings(): | |||
root = request.environ["SCRIPT_NAME"] | |||
cookies = parse_cookies(root, request.environ.get("HTTP_COOKIE")) | |||
return render_template("settings.mako", root=root, environ=request.environ, cookies=cookies) | |||
return render_template("settings.mako") | |||
@app.route("/debug") | |||
def debug(): | |||
root = request.environ["SCRIPT_NAME"] | |||
cookies = parse_cookies(root, request.environ.get("HTTP_COOKIE")) | |||
return render_template("debug.mako", root=root, environ=request.environ, cookies=cookies) | |||
return render_template("debug.mako") | |||
if __name__ == '__main__': | |||
WSGIServer(app).run() |
@@ -7,16 +7,14 @@ import re | |||
from time import time | |||
from earwigbot import exceptions | |||
from flask import g | |||
from .misc import get_bot, open_sql_connection | |||
_descurl = None | |||
def set_background(context, cookies, selected): | |||
global _descurl | |||
def set_background(context, selected): | |||
conn = open_sql_connection(get_bot(), "globals") | |||
if "CopyviosScreenCache" in cookies: | |||
cache = cookies["CopyviosScreenCache"].value | |||
if "CopyviosScreenCache" in g.cookies: | |||
cache = g.cookies["CopyviosScreenCache"].value | |||
try: | |||
screen = loads(cache) | |||
int(screen["width"]) | |||
@@ -32,12 +30,9 @@ def set_background(context, cookies, selected): | |||
info = _update_url(conn, "background_list", 2, _get_fresh_list) | |||
filename, url, descurl, width, height = info | |||
bg_url = _build_url(screen, filename, url, width, height) | |||
_descurl = descurl | |||
g.descurl = descurl | |||
return bg_url | |||
def get_desc_url(context): | |||
return _descurl | |||
def _update_url(conn, service, bg_id, callback): | |||
query1 = "SELECT update_time FROM updates WHERE update_service = ?" | |||
query2 = "SELECT 1 FROM background WHERE background_id = ?" | |||
@@ -4,6 +4,8 @@ import base64 | |||
from Cookie import CookieError, SimpleCookie | |||
from datetime import datetime, timedelta | |||
from flask import g | |||
class _CookieManager(SimpleCookie): | |||
MAGIC = "--cpv2" | |||
@@ -40,14 +42,15 @@ class _CookieManager(SimpleCookie): | |||
def parse_cookies(path, cookies): | |||
return _CookieManager(path, cookies) | |||
def set_cookie(headers, cookies, key, value, days=0): | |||
cookies[key] = value | |||
def set_cookie(key, value, days=0): | |||
g.cookies[key] = value | |||
if days: | |||
expires = datetime.utcnow() + timedelta(days=days) | |||
cookies[key]["expires"] = expires.strftime("%a, %d %b %Y %H:%M:%S GMT") | |||
cookies[key]["path"] = cookies.path | |||
headers.append(("Set-Cookie", cookies[key].OutputString())) | |||
def delete_cookie(headers, cookies, key): | |||
set_cookie(headers, cookies, key, u"", days=-1) | |||
del cookies[key] | |||
expire_dt = datetime.utcnow() + timedelta(days=days) | |||
expires = expire_dt.strftime("%a, %d %b %Y %H:%M:%S GMT") | |||
g.cookies[key]["expires"] = expires | |||
g.cookies[key]["path"] = g.cookies.path | |||
g.new_cookies.append(g.cookies[key].OutputString()) | |||
def delete_cookie(key): | |||
set_cookie(key, u"", days=-1) | |||
del g.cookies[key] |
@@ -4,19 +4,20 @@ from os.path import expanduser | |||
from urlparse import parse_qs | |||
from earwigbot.bot import Bot | |||
from flask import request | |||
import oursql | |||
_bot = None | |||
_connections = {} | |||
class Query(object): | |||
def __init__(self, environ, method="GET"): | |||
def __init__(self, method="GET"): | |||
self.query = {} | |||
if method == "GET": | |||
parsed = parse_qs(environ["QUERY_STRING"]) | |||
parsed = parse_qs(request.environ["QUERY_STRING"]) | |||
elif method == "POST": | |||
size = int(environ.get("CONTENT_LENGTH", 0)) | |||
parsed = parse_qs(environ["wsgi.input"].read(size)) | |||
size = int(request.environ.get("CONTENT_LENGTH", 0)) | |||
parsed = parse_qs(request.environ["wsgi.input"].read(size)) | |||
else: | |||
parsed = {} | |||
for key, value in parsed.iteritems(): | |||
@@ -50,8 +51,9 @@ def open_sql_connection(bot, dbname): | |||
conn_args = bot.config.wiki["_copyviosSQL"][dbname] | |||
if "read_default_file" not in conn_args and "user" not in conn_args and "passwd" not in conn_args: | |||
conn_args["read_default_file"] = expanduser("~/.my.cnf") | |||
elif "read_default_file" in args: | |||
args["read_default_file"] = expanduser(args["read_default_file"]) | |||
elif "read_default_file" in conn_args: | |||
default_file = expanduser(conn_args["read_default_file"]) | |||
conn_args["read_default_file"] = default_file | |||
if "autoping" not in conn_args: | |||
conn_args["autoping"] = True | |||
if "autoreconnect" not in conn_args: | |||
@@ -1,17 +1,18 @@ | |||
# -*- coding: utf-8 -*- | |||
from flask import g | |||
from markupsafe import escape | |||
from .cookies import set_cookie, delete_cookie | |||
from .misc import get_bot, Query | |||
from .sites import get_sites | |||
def main(context, environ, headers, cookies): | |||
query = Query(environ, method="POST") | |||
def main(context): | |||
query = Query(method="POST") | |||
if query.action == "set": | |||
status = _do_set(query, headers, cookies) | |||
status = _do_set(query) | |||
elif query.action == "delete": | |||
status = _do_delete(query, headers, cookies) | |||
status = _do_delete(query) | |||
else: | |||
status = None | |||
@@ -19,37 +20,39 @@ def main(context, environ, headers, cookies): | |||
langs, projects = get_sites(bot) | |||
return bot, status, langs, projects | |||
def _do_set(query, headers, cookies): | |||
def _do_set(query): | |||
cookies = g.cookies | |||
changes = set() | |||
if query.lang: | |||
key = "CopyviosDefaultLang" | |||
if key not in cookies or cookies[key].value != query.lang: | |||
set_cookie(headers, cookies, key, query.lang, 1095) | |||
set_cookie(key, query.lang, 1095) | |||
changes.add("site") | |||
if query.project: | |||
key = "CopyviosDefaultProject" | |||
if key not in cookies or cookies[key].value != query.project: | |||
set_cookie(headers, cookies, key, query.project, 1095) | |||
set_cookie(key, query.project, 1095) | |||
changes.add("site") | |||
if query.background: | |||
key = "CopyviosBackground" | |||
if key not in cookies or cookies[key].value != query.background: | |||
set_cookie(headers, cookies, key, query.background, 1095) | |||
delete_cookie(headers, cookies, "EarwigBackgroundCache") | |||
set_cookie(key, query.background, 1095) | |||
delete_cookie("EarwigBackgroundCache") | |||
changes.add("background") | |||
if changes: | |||
changes = ", ".join(sorted(list(changes))) | |||
return "Updated {0}.".format(changes) | |||
return None | |||
def _do_delete(query, headers, cookies): | |||
def _do_delete(query): | |||
cookies = g.cookies | |||
if query.cookie in cookies: | |||
delete_cookie(headers, cookies, query.cookie.encode("utf8")) | |||
delete_cookie(query.cookie.encode("utf8")) | |||
template = u'Deleted cookie <b><span class="mono">{0}</span></b>.' | |||
return template.format(escape(query.cookie)) | |||
elif query.all: | |||
number = len(cookies) | |||
for cookie in cookies.values(): | |||
delete_cookie(headers, cookies, cookie.key) | |||
delete_cookie(cookie.key) | |||
return "Deleted <b>{0}</b> cookies.".format(number) | |||
return None |
@@ -1,11 +1,10 @@ | |||
<%include file="/support/header.mako" args="title='Debug - Earwig\'s Copyvio Detector', root=root, cookies=cookies"/> | |||
<%include file="/support/header.mako" args="title='Debug - Earwig\'s Copyvio Detector'"/> | |||
<%! from flask import request %>\ | |||
<ul> | |||
% for key, value in environ.items(): | |||
% for key, value in request.environ.items(): | |||
% if key not in ["wsgi.input", "wsgi.errors", "PATH"]: | |||
<li><b>${key}</b>: ${value | h}</li> | |||
% elif key == "wsgi.input": | |||
<li><b>${key}</b>: ${value.read(int(environ.get("CONTENT_LENGTH", 0))) | h}</li> | |||
% endif | |||
% endfor | |||
</ul> | |||
<%include file="/support/footer.mako" args="cookies=cookies"/> | |||
<%include file="/support/footer.mako"/> |
@@ -1,4 +1,4 @@ | |||
<%include file="/support/header.mako" args="title='Earwig\'s Copyvio Detector', root=root, cookies=cookies"/> | |||
<%include file="/support/header.mako" args="title='Earwig\'s Copyvio Detector'"/> | |||
<%namespace module="copyvios" import="main, highlight_delta"/>\ | |||
<%namespace module="copyvios.misc" import="urlstrip"/>\ | |||
<% | |||
@@ -158,4 +158,4 @@ | |||
</div> | |||
</div> | |||
% endif | |||
<%include file="/support/footer.mako" args="cookies=cookies"/> | |||
<%include file="/support/footer.mako"/> |
@@ -1,21 +1,25 @@ | |||
<%namespace module="copyvios.settings" import="main"/>\ | |||
<% bot, status, langs, projects = main(environ, headers, cookies) %>\ | |||
<%include file="/support/header.mako" args="title='Settings - Earwig\'s Copyvio Detector', root=root, cookies=cookies"/> | |||
<%! from json import dumps, loads %>\ | |||
<%! | |||
from json import dumps, loads | |||
from flask import g, request | |||
from copyvios.settings import main | |||
%>\ | |||
<% bot, status, langs, projects = main() %>\ | |||
<%include file="/support/header.mako" args="title='Settings - Earwig\'s Copyvio Detector'"/> | |||
% if status: | |||
<div id="info-box" class="green-box"> | |||
<p>${status}</p> | |||
</div> | |||
% endif | |||
<p>This page contains some configurable options for the copyvio detector. Settings are saved as cookies. You can view and delete all cookies generated by this site at the bottom of this page.</p> | |||
<form action="${environ['REQUEST_URI']}" method="post"> | |||
<form action="${request.base_url}" method="post"> | |||
<table> | |||
<tr> | |||
<td>Default site:</td> | |||
<td> | |||
<span class="mono">http://</span> | |||
<select name="lang"> | |||
<% selected_lang = cookies["CopyviosDefaultLang"].value if "CopyviosDefaultLang" in cookies else bot.wiki.get_site().lang %>\ | |||
<% selected_lang = g.cookies["CopyviosDefaultLang"].value if "CopyviosDefaultLang" in g.cookies else bot.wiki.get_site().lang %>\ | |||
% for code, name in langs: | |||
% if code == selected_lang: | |||
<option value="${code | h}" selected="selected">${name}</option> | |||
@@ -26,7 +30,7 @@ | |||
</select> | |||
<span class="mono">.</span> | |||
<select name="project"> | |||
<% selected_project = cookies["CopyviosDefaultProject"].value if "CopyviosDefaultProject" in cookies else bot.wiki.get_site().project %>\ | |||
<% selected_project = g.cookies["CopyviosDefaultProject"].value if "CopyviosDefaultProject" in g.cookies else bot.wiki.get_site().project %>\ | |||
% for code, name in projects: | |||
% if code == selected_project: | |||
<option value="${code | h}" selected="selected">${name}</option> | |||
@@ -44,7 +48,7 @@ | |||
("potd", 'Use the current Commons Picture of the Day, unfiltered. Certain POTDs may be unsuitable as backgrounds due to their aspect ratio or subject matter.'), | |||
("plain", "Use a plain background."), | |||
] | |||
selected = cookies["CopyviosBackground"].value if "CopyviosBackground" in cookies else "list" | |||
selected = g.cookies["CopyviosBackground"].value if "CopyviosBackground" in g.cookies else "list" | |||
%>\ | |||
% for i, (value, desc) in enumerate(background_options): | |||
<tr> | |||
@@ -67,11 +71,11 @@ | |||
</table> | |||
</form> | |||
<h2>Cookies</h2> | |||
% if cookies: | |||
% if g.cookies: | |||
<table> | |||
<% cookie_order = ["CopyviosDefaultProject", "CopyviosDefaultLang", "CopyviosBackground", "CopyviosShowDetails", "CopyviosScreenCache"] %>\ | |||
% for key in [key for key in cookie_order if key in cookies]: | |||
<% cookie = cookies[key] %>\ | |||
% for key in [key for key in cookie_order if key in g.cookies]: | |||
<% cookie = g.cookies[key] %>\ | |||
<tr> | |||
<td><b><span class="mono">${key | h}</span></b></td> | |||
% try: | |||
@@ -85,7 +89,7 @@ | |||
<td><span class="mono">${cookie.value | h}</span></td> | |||
% endtry | |||
<td> | |||
<form action="${environ['REQUEST_URI']}" method="post"> | |||
<form action="${request.base_url}" method="post"> | |||
<input type="hidden" name="action" value="delete"> | |||
<input type="hidden" name="cookie" value="${key | h}"> | |||
<button type="submit">Delete</button> | |||
@@ -95,7 +99,7 @@ | |||
% endfor | |||
<tr> | |||
<td> | |||
<form action="${environ['REQUEST_URI']}" method="post"> | |||
<form action="${request.base_url}" method="post"> | |||
<input type="hidden" name="action" value="delete"> | |||
<input type="hidden" name="all" value="1"> | |||
<button type="submit">Delete all</button> | |||
@@ -106,4 +110,4 @@ | |||
% else: | |||
<p>No cookies!</p> | |||
% endif | |||
<%include file="/support/footer.mako" args="cookies=cookies"/> | |||
<%include file="/support/footer.mako"/> |
@@ -1,11 +1,10 @@ | |||
<%page args="cookies"/>\ | |||
<%namespace module="copyvios.background" import="get_desc_url"/>\ | |||
<%! from flask import g %>\ | |||
</div> | |||
<div id="footer"> | |||
<p>Copyright © 2009–2014 <a href="//en.wikipedia.org/wiki/User:The_Earwig">Ben Kurtovic</a> • \ | |||
<a href="https://github.com/earwig/copyvios">View Source</a> • \ | |||
% if ("CopyviosBackground" in cookies and cookies["CopyviosBackground"].value in ["potd", "list"]) or "CopyviosBackground" not in cookies: | |||
<a href="${get_desc_url() | h}">Background</a> • \ | |||
% if ("CopyviosBackground" in g.cookies and g.cookies["CopyviosBackground"].value in ["potd", "list"]) or "CopyviosBackground" not in g.cookies: | |||
<a href="${g.descurl | h}">Background</a> • \ | |||
% endif | |||
<a href="http://validator.w3.org/check?uri=referer">Valid HTML5</a> | |||
</p> | |||
@@ -1,24 +1,27 @@ | |||
<%page args="title, root, cookies"/>\ | |||
<%namespace module="copyvios.background" import="set_background"/>\ | |||
<%page args="title"/>\ | |||
<%! | |||
from flask import g, request | |||
from copyvios.background import set_background | |||
%>\ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="utf-8"> | |||
<title>${title}</title> | |||
<link rel="stylesheet" href="${root}/static/style.min.css" type="text/css" /> | |||
<script src="${root}/static/script.min.js" type="text/javascript"></script> | |||
<link rel="stylesheet" href="${request.script_root}/static/style.min.css" type="text/css" /> | |||
<script src="${request.script_root}/static/script.min.js" type="text/javascript"></script> | |||
</head> | |||
<% selected = cookies["CopyviosBackground"].value if "CopyviosBackground" in cookies else "list" %>\ | |||
<% selected = g.cookies["CopyviosBackground"].value if "CopyviosBackground" in g.cookies else "list" %>\ | |||
% if selected == "plain": | |||
<body style="background-image: url('${root}/static/background.png');"> | |||
<body style="background-image: url('${request.script_root}/static/background.png');"> | |||
% else: | |||
<body onload="update_screen_size()" style="background-image: url('${set_background(cookies, selected) | h}'); background-size: cover;"> | |||
<body onload="update_screen_size()" style="background-image: url('${set_background(selected) | h}'); background-size: cover;"> | |||
% endif | |||
<div id="header"> | |||
<table id="heading"> | |||
<tr> | |||
<td id="head-home"><a id="a-home" href="${root}">Earwig's Copyvio Detector</a></td> | |||
<td id="head-settings"><a id="a-settings" href="${root}/settings">Settings</a></td> | |||
<td id="head-home"><a id="a-home" href="${request.script_root}">Earwig's Copyvio Detector</a></td> | |||
<td id="head-settings"><a id="a-settings" href="${request.script_root}/settings">Settings</a></td> | |||
</tr> | |||
</table> | |||
</div> | |||