Преглед изворни кода

Switching a bit of code from client-side to server-side.

- All POTD logic is now in Python instead of JS.
- Removed EarwigBackgroundCache cookie (now stored in a new `background` table in the database).
- Added EarwigScreenCache cookie
- Increase cookie life from a year to three.
pull/24/head
Ben Kurtovic пре 11 година
родитељ
комит
3de23628b7
9 измењених фајлова са 168 додато и 182 уклоњено
  1. +1
    -1
      pages/settings.mako
  2. +2
    -1
      pages/support/footer.mako
  3. +3
    -3
      pages/support/header.mako
  4. +15
    -0
      schema.sql
  5. +1
    -1
      static/js/copyvios.js
  6. +14
    -169
      static/js/potd.js
  7. +115
    -0
      toolserver/background.py
  8. +14
    -4
      toolserver/misc.py
  9. +3
    -3
      toolserver/settings.py

+ 1
- 1
pages/settings.mako Прегледај датотеку

@@ -69,7 +69,7 @@
<h2>Cookies</h2>
% if cookies:
<table>
<% cookie_order = ["EarwigDefaultProject", "EarwigDefaultLang", "EarwigBackground", "EarwigCVShowDetails", "EarwigBackgroundCache"] %>\
<% cookie_order = ["EarwigDefaultProject", "EarwigDefaultLang", "EarwigBackground", "EarwigScreenCache", "EarwigCVShowDetails"] %>\
% for key in [key for key in cookie_order if key in cookies]:
<% cookie = cookies[key] %>\
<tr>


+ 2
- 1
pages/support/footer.mako Прегледај датотеку

@@ -1,4 +1,5 @@
<%page args="environ, cookies"/>\
<%namespace module="toolserver.background" import="get_desc_url"/>\
<%!
from os import path
%>\
@@ -19,7 +20,7 @@
<a href="mailto:earwig@toolserver.org">Contact</a> &bull; \
<a href="https://github.com/earwig/toolserver">View Source</a> &bull; \
% if ("EarwigBackground" in cookies and cookies["EarwigBackground"].value in ["potd", "list"]) or "EarwigBackground" not in cookies:
<a id="bg_image_link" href="">Background</a> &bull; \
<a href="${get_desc_url() | h}">Background</a> &bull; \
% endif
<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0 Strict</a>
</p>


+ 3
- 3
pages/support/header.mako Прегледај датотеку

@@ -1,4 +1,5 @@
<%page args="environ, cookies, title, slug=None, add_css=(), add_js=()"/>\
<%namespace module="toolserver.background" import="set_background"/>\
<%namespace name="index" file="/index.mako" import="get_tools"/>\
<%!
from os import path
@@ -31,10 +32,9 @@
<% selected = cookies["EarwigBackground"].value if "EarwigBackground" in cookies else "list" %>\
% if selected in ["plain-brown", "plain-blue"]:
<body style="background-image: url('${root}/static/images/background-${selected[6:]}.png');">
% elif selected == "potd":
<body onload="set_background_potd()" style="background-repeat: no-repeat;">
% else:
<body onload="set_background_list()" style="background-repeat: no-repeat;">
<% bg_url = set_background(cookies, selected) %>\
<body onload="update_screen_size()" style="background-image: url('${bg_url | h}'); background-size: cover;">
% endif
<div id="header">
<p id="heading"><a class="dark" href="${pretty}">earwig</a><span class="light">@</span><a class="mid" href="https://wiki.toolserver.org/">toolserver</a><span class="light">:</span><a class="dark" href="${this}">${slug}</a></p>


+ 15
- 0
schema.sql Прегледај датотеку

@@ -10,6 +10,21 @@ CREATE DATABASE `u_earwig_toolserver`
DEFAULT COLLATE utf8_unicode_ci;

--
-- Table structure for table `background`
--

DROP TABLE IF EXISTS `background`;
CREATE TABLE `background` (
`background_id` int(9) unsigned NOT NULL,
`background_filename` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`background_url` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`background_descurl` varchar(512) COLLATE utf8_unicode_ci DEFAULT NULL,
`background_width` int(9) unsigned DEFAULT NULL,
`background_height` int(9) unsigned DEFAULT NULL,
PRIMARY KEY (`background_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Table structure for table `language`
--



+ 1
- 1
static/js/copyvios.js Прегледај датотеку

@@ -5,7 +5,7 @@ function copyvio_toggle_details(details) {
if (link.innerHTML == "Show details:") {
details.style.display = "block";
link.innerHTML = "Hide details:";
set_cookie("EarwigCVShowDetails", "True", 365);
set_cookie("EarwigCVShowDetails", "True", 1095);
} else {
details.style.display = "none";
link.innerHTML = "Show details:";


+ 14
- 169
static/js/potd.js Прегледај датотеку

@@ -1,181 +1,26 @@
function set_background_potd() {
if (cache_cookie()) return;
var d = new Date();
var callback = "earwigpotd1";
var date = (d.getUTCFullYear()) + "-" + zero_pad(d.getUTCMonth() + 1, 2) + "-" + zero_pad(d.getUTCDate(), 2);
var base = "//commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=Template:Potd/";
var url = base + date + "&callback=" + callback;

var script = document.createElement("script");
var head = document.getElementsByTagName("head")[0];

window[callback] = function(data) {
head.removeChild(script);
parse_potd_file_name(data);
};

script.src = url;
head.appendChild(script);
}

function set_background_list() {
if (cache_cookie()) return;
var callback = "earwigpotd1";
var base = "//commons.wikimedia.org/w/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=User:The+Earwig/POTD";
var url = base + "&callback=" + callback;

var script = document.createElement("script");
var head = document.getElementsByTagName("head")[0];

window[callback] = function(data) {
head.removeChild(script);
parse_list_file_name(data);
};

script.src = url;
head.appendChild(script);
function update_screen_size() {
var cache = cache_cookie();
var data = {
"width": window.screen.availWidth,
"height": window.screen.availHeight
}
if (!cookie || cookie["width"] != data["width"] || cookie["height"] != data["height"]) {
set_cookie("EarwigScreenCache", JSON.stringify(data), 1095);
}
}

function cache_cookie() {
var cookie = get_cookie("EarwigBackgroundCache");
var cookie = get_cookie("EarwigScreenCache");
if (cookie) {
try {
data = JSON.parse(cookie);
var filename = data.filename;
var url = data.url;
var descurl = data.descurl;
var imgwidth = data.imgwidth;
var imgheight = data.imgheight;
if (filename && url && descurl && imgwidth && imgheight) {
set_background(filename, url, descurl, imgwidth, imgheight);
return true;
var width = data.width;
var height = data.height;
if (width && height) {
return {"width": width, "height": height};
}
}
catch (SyntaxError) {}
}
return false;
}

function parse_potd_file_name(data) {
var content = "";
var res = data["query"]["pages"];
for (pageid in res) {
content = res[pageid]["revisions"][0]["*"];
}
var filename = /\{\{Potd filename\|(1=)?(.*?)\|.*?\}\}/.exec(content)[2];

var callback = "earwigpotd2";
var base = "//commons.wikimedia.org/w/api.php?action=query&prop=imageinfo&iiprop=url|size&format=json&titles=File:";
var url = base + escape(filename) + "&callback=" + callback;

var script = document.createElement("script");
var head = document.getElementsByTagName("head")[0];

window[callback] = function(data) {
head.removeChild(script);
parse_file_url(data, escape(filename.replace(/ /g, "_")));
};

script.src = url;
head.appendChild(script);
}

function parse_list_file_name(data) {
var content = "";
var res = data["query"]["pages"];
for (pageid in res) {
content = res[pageid]["revisions"][0]["*"];
}

var filenames = [];
var regexp = /\*\*?\s*\[\[:File:(.*?)\]\]/g;
while ((match = regexp.exec(content)) !== null) {
filenames.push(match[1]);
}
var filename = filenames[Math.floor(Math.random() * filenames.length)];

var callback = "earwigpotd2";
var base = "//commons.wikimedia.org/w/api.php?action=query&prop=imageinfo&iiprop=url|size&format=json&titles=File:";
var url = base + escape(filename) + "&callback=" + callback;

var script = document.createElement("script");
var head = document.getElementsByTagName("head")[0];

window[callback] = function(data) {
head.removeChild(script);
parse_file_url(data, escape(filename.replace(/ /g, "_")));
};

script.src = url;
head.appendChild(script);
}

function parse_file_url(data, filename) {
var url = "";
var descurl = "";
var imgwidth = 1024;
var imgheight = 768;

var res = data["query"]["pages"];
for (pageid in res) {
r = res[pageid]["imageinfo"][0];
url = r["url"];
descurl = r["descriptionurl"];
imgwidth = r["width"];
imgheight = r["height"];
}

set_background(filename, url, descurl, imgwidth, imgheight);
var data = {"filename": filename, "url": url, "descurl": descurl, "imgwidth": imgwidth, "imgheight": imgheight};
var expires = new Date();
expires.setUTCMilliseconds(0);
expires.setUTCSeconds(0);
expires.setUTCMinutes(0);
expires.setUTCHours(0);
expires.setUTCDate(expires.getUTCDate() + 1);
set_cookie_with_date("EarwigBackgroundCache", JSON.stringify(data), expires);
}

function set_background(filename, url, descurl, imgwidth, imgheight) {
var s = get_window_size();
var winwidth = s[0];
var winheight = s[1];

var width = winwidth;
if (imgwidth/imgheight > winwidth/winheight) {
width = Math.round((imgwidth/imgheight) * winheight);
}
if (width >= imgwidth) {
document.body.style.backgroundImage = "url('" + url + "')";
if (width > imgwidth) {
document.body.style.setProperty("background-size", "cover");
}
} else {
url = url.replace(/\/commons\//, "/commons/thumb/") + "/" + width + "px-" + filename;
document.body.style.backgroundImage = "url('" + url + "')";
}
document.getElementById("bg_image_link").href = descurl;
}

function zero_pad(value, length) {
value = String(value);
length = length || 2;
while (value.length < length) {
value = "0" + value;
}
return value;
}

function get_window_size() {
// See http://www.javascripter.net/faq/browserw.htm
if (document.body && document.body.offsetWidth && document.body.offsetHeight) {
return [document.body.offsetWidth, document.body.offsetHeight];
}
if (document.compatMode=="CSS1Compat" && document.documentElement && document.documentElement.offsetWidth && document.documentElement.offsetHeight) {
return [document.documentElement.offsetWidth, document.documentElement.offsetHeight];
}
if (window.innerWidth && window.innerHeight) {
return [window.innerWidth, window.innerHeight];
}
return [1024, 768];
}

+ 115
- 0
toolserver/background.py Прегледај датотеку

@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-

from datetime import datetime, timedelta
from json import loads
import random
import re
from time import time

from earwigbot import exceptions

from .misc import get_bot, open_sql_connection

_descurl = None

def set_background(cookies, selected):
global _descurl
conn = open_sql_connection(get_bot(), "globals")
if "EarwigScreenCache" in cookies:
cache = cookies["EarwigScreenCache"].value
try:
screen = loads(cache)
int(screen["width"])
int(screen["height"])
except (ValueError, KeyError):
screen = {"width": 1024, "height": 768}
else:
screen = {"width": 1024, "height": 768}

if selected == "potd":
info = _update_url(conn, "background_potd", 1, _get_fresh_potd)
else:
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
return bg_url

def get_desc_url():
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 = ?"
query3 = "DELETE FROM background WHERE background_id = ?"
query4 = "INSERT INTO background VALUES (?, ?, ?, ?, ?, ?)"
query5 = "SELECT 1 FROM updates WHERE update_service = ?"
query6 = "UPDATE updates SET update_time = ? WHERE update_service = ?"
query7 = "INSERT INTO updates VALUES (?, ?)"
query8 = "SELECT * FROM background WHERE background_id = ?"
with conn.cursor() as cursor:
cursor.execute(query1, (service,))
try:
update_time = datetime.utcfromtimestamp(cursor.fetchall()[0][0])
except IndexError:
update_time = datetime.min
plus_one = update_time + timedelta(days=1)
max_age = datetime(plus_one.year, plus_one.month, plus_one.day)
if datetime.utcnow() > max_age:
filename, url, descurl, width, height = callback()
cursor.execute(query2, (bg_id,))
if cursor.fetchall():
cursor.execute(query3, (bg_id,))
cursor.execute(query4, (bg_id, filename, url, descurl, width,
height))
cursor.execute(query5, (service,))
if cursor.fetchall():
cursor.execute(query6, (time(), service))
else:
cursor.execute(query7, (service, time()))
else:
cursor.execute(query8, (bg_id,))
filename, url, descurl, width, height = cursor.fetchone()[1:]
return filename, url, descurl, width, height

def _get_fresh_potd():
site = _get_site()
date = datetime.utcnow().strftime("%Y-%m-%d")
page = site.get_page("Template:Potd/" + date)
regex = ur"\{\{Potd filename\|(?:1=)?(.*?)\|.*?\}\}"
filename = re.search(regex, page.get()).group(1)
return _load_file(site, filename)

def _get_fresh_list():
site = _get_site()
page = site.get_page("User:The Earwig/POTD")
regex = ur"\*\*?\s*\[\[:File:(.*?)\]\]"
filenames = re.findall(regex, page.get())
filename = random.choice(filenames)
return _load_file(site, filename)

def _load_file(site, filename):
res = site.api_query(action="query", prop="imageinfo", iiprop="url|size",
titles="File:" + filename)
data = res["query"]["pages"].values()[0]["imageinfo"][0]
url = data["url"]
descurl = data["descriptionurl"]
width = data["width"]
height = data["height"]
return filename.replace(" ", "_"), url, descurl, width, height

def _get_site():
bot = get_bot()
try:
return bot.wiki.get_site("commonswiki")
except exceptions.SiteNotFoundError:
return bot.wiki.add_site(project="wikimedia", lang="commons")

def _build_url(screen, filename, url, imgwidth, imgheight):
width = screen["width"]
if float(imgwidth) / imgheight > float(screen["width"]) / screen["height"]:
width = int(float(imgwidth) / imgheight * screen["width"])
if width >= imgwidth:
return url
url = url.replace("/commons/", "/commons/thumb/")
return url + "/" + width + "px-" + filename

+ 14
- 4
toolserver/misc.py Прегледај датотеку

@@ -6,6 +6,9 @@ from urlparse import parse_qs
from earwigbot.bot import Bot
import oursql

_bot = None
_connections = {}

class Query(object):
def __init__(self, environ, method="GET"):
self.query = {}
@@ -35,7 +38,15 @@ class Query(object):
self.query[key] = value


def get_bot():
global _bot
if not _bot:
_bot = Bot(".earwigbot", 100) # Don't print any logs to the console
return _bot

def open_sql_connection(bot, dbname):
if dbname in _connections:
return _connections[dbname]
conn_args = bot.config.wiki["_toolserverSQL"][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")
@@ -43,7 +54,9 @@ def open_sql_connection(bot, dbname):
conn_args["autoping"] = True
if "autoreconnect" not in conn_args:
conn_args["autoreconnect"] = True
return oursql.connect(**conn_args)
conn = oursql.connect(**conn_args)
_connections[dbname] = conn
return conn

def urlstrip(context, url):
if url.startswith("http://"):
@@ -55,6 +68,3 @@ def urlstrip(context, url):
if url.endswith("/"):
url = url[:-1]
return url

def get_bot():
return Bot(".earwigbot", 100) # Don't print any logs to the console

+ 3
- 3
toolserver/settings.py Прегледај датотеку

@@ -25,17 +25,17 @@ def _do_set(query, headers, cookies):
if query.lang:
key = "EarwigDefaultLang"
if key not in cookies or cookies[key].value != query.lang:
set_cookie(headers, cookies, key, query.lang, 365)
set_cookie(headers, cookies, key, query.lang, 1095)
changes.add("site")
if query.project:
key = "EarwigDefaultProject"
if key not in cookies or cookies[key].value != query.project:
set_cookie(headers, cookies, key, query.project, 365)
set_cookie(headers, cookies, key, query.project, 1095)
changes.add("site")
if query.background:
key = "EarwigBackground"
if key not in cookies or cookies[key].value != query.background:
set_cookie(headers, cookies, key, query.background, 365)
set_cookie(headers, cookies, key, query.background, 1095)
delete_cookie(headers, cookies, "EarwigBackgroundCache")
changes.add("background")
if changes:


Loading…
Откажи
Сачувај