From 031daa32bbe11417d0dfb968dfbf888f0dc65d86 Mon Sep 17 00:00:00 2001 From: raylu Date: Sun, 20 Oct 2013 03:07:32 -0700 Subject: rewrite as api --- config.py | 3 +- config.yaml.example | 5 ++-- db/queries.py | 56 ++++++++++++++++++++++++++++++++++ server.py | 68 +++++++----------------------------------- web/api.py | 57 +++++++++++++++++++++++++++++++++++ web/static/js/common.js | 6 ++++ web/static/js/corporation.js | 49 ++++++++++++++++++++++++++++++ web/static/js/kill.js | 30 +++++++++++++++++++ web/static/js/search.js | 11 +++++++ web/templates/base.html | 7 +++++ web/templates/corporation.html | 26 ++++------------ web/templates/kill.html | 21 +++++-------- web/templates/search.html | 10 +++---- 13 files changed, 248 insertions(+), 101 deletions(-) create mode 100644 db/queries.py create mode 100644 web/api.py create mode 100644 web/static/js/common.js create mode 100644 web/static/js/corporation.js create mode 100644 web/static/js/kill.js create mode 100644 web/static/js/search.js diff --git a/config.py b/config.py index 46df4d4..426d968 100644 --- a/config.py +++ b/config.py @@ -13,7 +13,8 @@ class WebConfig(Config): attrs = frozenset([ 'port', 'host', - 'cookie_secret', + 'api_port', + 'api_host', 'debug', ]) diff --git a/config.yaml.example b/config.yaml.example index d521366..f29bfdd 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -1,7 +1,8 @@ web: port: 8888 - host: 'localhost:8888' - cookie_secret: 'dis is super sekrit' + host: 'http://localhost:8888' + api_port: 8887 + api_host: 'http://localhost:8887' debug: true db: diff --git a/db/queries.py b/db/queries.py new file mode 100644 index 0000000..f795b39 --- /dev/null +++ b/db/queries.py @@ -0,0 +1,56 @@ +from collections import defaultdict +import operator +import db + +def search(q): + with db.cursor() as c: + corps = db.query(c, ''' + SELECT DISTINCT corporation_id, corporation_name FROM characters + WHERE corporation_name LIKE ? + ''', '%{}%'.format(q)) + return {'corporations': corps} + +def corporation(corp_id): + with db.cursor() as c: + kills = db.query(c, ''' + SELECT DISTINCT(kills.kill_id), kill_time FROM kills + JOIN characters on characters.kill_id = kills.kill_id + WHERE corporation_id = ? + ''', corp_id) + kill_ids = list(map(operator.itemgetter('kill_id'), kills)) + char_rows = db.query(c, ''' + SELECT + kill_id, victim, final_blow, + character_id, character_name, corporation_id, corporation_name, alliance_id, alliance_name, faction_id, faction_name + FROM characters + WHERE kill_id IN ({}) + '''.format(','.join(map(str, kill_ids)))) + characters = defaultdict(dict) + for char in char_rows: + kill_id = char['kill_id'] + if char['victim']: + characters[kill_id]['victim'] = char + elif char['final_blow']: + characters[kill_id]['final_blow'] = char + for kill in kills: + chars = characters[kill['kill_id']] + kill['victim'] = chars['victim'] + kill['final_blow'] = chars['final_blow'] + return kills + +def kill(kill_id): + with db.cursor() as c: + kill = db.get(c, ''' + SELECT kill_time, solarSystemName, security FROM kills + JOIN eve.mapSolarSystems on solar_system_id = solarSystemID + WHERE kill_id = ? + ''', kill_id) + characters = db.query(c, ''' + SELECT ship_type_id, character_id, character_name, + corporation_id, corporation_name, alliance_id, alliance_name, faction_id, faction_name + typeName + FROM characters + JOIN eve.invTypes on ship_type_id = typeID + WHERE kill_id = ? + ''', kill_id) + return {'kill': kill, 'characters': characters} diff --git a/server.py b/server.py index 54afcc2..c68aaaf 100755 --- a/server.py +++ b/server.py @@ -1,8 +1,5 @@ #!/usr/bin/env python3 -from collections import defaultdict -import json -import operator import os import cleancss @@ -11,11 +8,11 @@ import tornado.ioloop import tornado.web from config import web as config -import db +import web.api class BaseHandler(tornado.web.RequestHandler): def render(self, *args, **kwargs): - kwargs['host'] = config.host + kwargs['api_host'] = config.api_host return super(BaseHandler, self).render(*args, **kwargs) def render_string(self, *args, **kwargs): @@ -28,60 +25,15 @@ class MainHandler(BaseHandler): class SearchHandler(BaseHandler): def get(self): - q = self.get_argument('q') - with db.cursor() as c: - corps = db.query(c, ''' - SELECT DISTINCT corporation_id, corporation_name FROM characters - WHERE corporation_name LIKE ? - ''', '%{}%'.format(q)) - self.render('search.html', corps=corps) + self.render('search.html') class CorporationHandler(BaseHandler): - def get(self, corp_id): - with db.cursor() as c: - kills = db.query(c, ''' - SELECT DISTINCT(kills.kill_id), kill_time FROM kills - JOIN characters on characters.kill_id = kills.kill_id - WHERE corporation_id = ? - ''', corp_id) - kill_ids = list(map(operator.itemgetter('kill_id'), kills)) - char_rows = db.query(c, ''' - SELECT - kill_id, victim, final_blow, - character_id, character_name, corporation_id, corporation_name, alliance_id, alliance_name, faction_id, faction_name - FROM characters - WHERE kill_id IN ({}) - '''.format(','.join(map(str, kill_ids)))) - characters = defaultdict(dict) - for char in char_rows: - kill_id = char['kill_id'] - if char['victim']: - characters[kill_id]['victim'] = char - elif char['final_blow']: - characters[kill_id]['final_blow'] = char - for kill in kills: - chars = characters[kill['kill_id']] - kill['victim'] = chars['victim'] - kill['final_blow'] = chars['final_blow'] - self.render('corporation.html', kills=kills) + def get(self): + self.render('corporation.html') class KillHandler(BaseHandler): - def get(self, kill_id): - with db.cursor() as c: - kill = db.get(c, ''' - SELECT kill_time, solarSystemName, security FROM kills - JOIN eve.mapSolarSystems on solar_system_id = solarSystemID - WHERE kill_id = ? - ''', kill_id) - characters = db.query(c, ''' - SELECT ship_type_id, character_id, character_name, - corporation_id, corporation_name, alliance_id, alliance_name, faction_id, faction_name - typeName - FROM characters - JOIN eve.invTypes on ship_type_id = typeID - WHERE kill_id = ? - ''', kill_id) - self.render('kill.html', kill=kill, characters=characters) + def get(self): + self.render('kill.html') class CSSHandler(tornado.web.RequestHandler): def get(self, css_path): @@ -95,13 +47,13 @@ if __name__ == '__main__': handlers=[ (r'/', MainHandler), (r'/search', SearchHandler), - (r'/corporation/(.+)', CorporationHandler), - (r'/kill/(.+)', KillHandler), + (r'/corporation/.+', CorporationHandler), + (r'/kill/.+', KillHandler), (r'/(css/.+)\.css', CSSHandler), ], template_path=os.path.join(os.path.dirname(__file__), 'web/templates'), - cookie_secret=config.cookie_secret, debug=config.debug, ).listen(config.port) + web.api.start() print('listening on :%d' % config.port) tornado.ioloop.IOLoop.instance().start() diff --git a/web/api.py b/web/api.py new file mode 100644 index 0000000..4993393 --- /dev/null +++ b/web/api.py @@ -0,0 +1,57 @@ +import datetime +import json + +import tornado.web + +from config import web as config +import db.queries + +class JSONDateEncoder(json.JSONEncoder): + def default(self, data): + if isinstance(data, datetime.datetime): + return str(data) + return super(JSONDateEncoder, self).default(data) + +class APIHandler(tornado.web.RequestHandler): + def set_default_headers(self): + self.set_header('Access-Control-Allow-Origin', '*') + self.set_header('Access-Control-Allow-Headers', 'X-Requested-With, X-Request') + + def compute_etag(self): + return None + + def respond_json(self, data): + self.set_header('Content-Type', 'application/json; charset=UTF-8') + for chunk in JSONDateEncoder().iterencode(data): + self.write(chunk) + self.finish() + + def options(self, *args): + return + +class SearchHandler(APIHandler): + def get(self): + q = self.get_argument('q') + data = db.queries.search(q) + self.respond_json(data) + +class CorporationHandler(APIHandler): + def get(self, corp_id): + kills = db.queries.corporation(corp_id) + self.respond_json(kills) + +class KillHandler(APIHandler): + def get(self, kill_id): + kill = db.queries.kill(kill_id) + self.respond_json(kill) + +def start(): + tornado.web.Application( + handlers=[ + (r'/search', SearchHandler), + (r'/corporation/(.+)', CorporationHandler), + (r'/kill/(.+)', KillHandler), + ], + debug=config.debug, + ).listen(config.api_port) + print('listening on :%d' % config.api_port) diff --git a/web/static/js/common.js b/web/static/js/common.js new file mode 100644 index 0000000..4592cbe --- /dev/null +++ b/web/static/js/common.js @@ -0,0 +1,6 @@ +window.ykill.api = function (path, cb) { + new Request.JSON({ + 'url': ykill.api_host + path, + 'onSuccess': cb, + }).get(); +} diff --git a/web/static/js/corporation.js b/web/static/js/corporation.js new file mode 100644 index 0000000..10a1753 --- /dev/null +++ b/web/static/js/corporation.js @@ -0,0 +1,49 @@ +window.addEvent('domready', function() { + var corp_id = document.location.pathname.split('/').getLast(); + ykill.api('/corporation/' + corp_id, function(kills) { + var div = $('kills'); + kills.each(function(kill) { + var a = new Element('a', {'href': '/kill/' + kill['kill_id']}); + a.appendText(kill['kill_time']); + + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Character/' + kill['victim']['character_id'] + '_32.jpg', + 'alt': kill['victim']['character_name'], + })); + a.appendText(kill['victim']['character_name']); + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Corporation/' + kill['victim']['corporation_id'] + '_32.png', + 'alt': kill['victim']['corporation_name'], + })); + a.appendText(kill['victim']['corporation_name']); + if (kill['victim']['alliance_id']) { + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Alliance/' + kill['victim']['alliance_id'] + '_32.png', + 'alt': kill['victim']['alliance_name'], + })); + a.appendText(kill['victim']['alliance_name']); + } + + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Character/' + kill['final_blow']['character_id'] + '_32.jpg', + 'alt': kill['final_blow']['character_name'], + })); + a.appendText(kill['final_blow']['character_name']); + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Corporation/' + kill['final_blow']['corporation_id'] + '_32.png', + 'alt': kill['final_blow']['corporation_name'], + })); + a.appendText(kill['final_blow']['corporation_name']); + if (kill['final_blow']['alliance_id']) { + a.adopt(new Element('img', { + 'src': '//image.eveonline.com/Alliance/' + kill['final_blow']['alliance_id'] + '_32.png', + 'alt': kill['final_blow']['alliance_name'], + })); + a.appendText(kill['final_blow']['alliance_name']); + } + + div.adopt(a); + div.adopt(new Element('br')); + }); + }); +}); diff --git a/web/static/js/kill.js b/web/static/js/kill.js new file mode 100644 index 0000000..67f819d --- /dev/null +++ b/web/static/js/kill.js @@ -0,0 +1,30 @@ +window.addEvent('domready', function() { + var kill_id = document.location.pathname.split('/').getLast(); + ykill.api('/kill/' + kill_id, function(data) { + var kill = data.kill; + $('kill_time').appendText(kill['kill_time']); + $('solar_system').appendText(kill['solarSystemName'] + ' (' + kill['security'].toFixed(1) + ')'); + + var div = $('characters'); + data.characters.each(function(char) { + div.adopt(new Element('img', { + 'src': '//image.eveonline.com/Character/' + char['character_id'] + '_64.jpg', + 'alt': char['character_name'], + })); + div.appendText(char['character_name']); + div.adopt(new Element('img', { + 'src': '//image.eveonline.com/Corporation/' + char['corporation_id'] + '_64.png', + 'alt': char['corporation_name'], + })); + div.appendText(char['corporation_name']); + if (char['alliance_id']) { + div.adopt(new Element('img', { + 'src': '//image.eveonline.com/Alliance/' + char['alliance_id'] + '_64.png', + 'alt': char['alliance_name'], + })); + div.appendText(char['alliance_name']); + } + div.adopt(new Element('br')); + }); + }); +}); diff --git a/web/static/js/search.js b/web/static/js/search.js new file mode 100644 index 0000000..faeb8fe --- /dev/null +++ b/web/static/js/search.js @@ -0,0 +1,11 @@ +window.addEvent('domready', function() { + ykill.api('/search' + document.location.search, function(results) { + var corps = $('corps'); + results.corporations.each(function(corp) { + corps.grab(new Element('a', { + 'html': corp.corporation_name, + 'href': '/corporation/' + corp.corporation_id, + })); + }); + }); +}); diff --git a/web/templates/base.html b/web/templates/base.html index afd3c68..ffbe99b 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -3,6 +3,13 @@ + + + {% block js %}{% end %}
diff --git a/web/templates/corporation.html b/web/templates/corporation.html index 0afe4c3..66eceb2 100644 --- a/web/templates/corporation.html +++ b/web/templates/corporation.html @@ -1,27 +1,11 @@ {% extends "base.html" %} +{% block js %} + +{% end %} + {% block main %} -{% for kill in kills %} - - {{ kill['kill_time'] }} - {{ kill['victim']['character_name'] }} - {{ kill['victim']['character_name'] }} - {{ kill['victim']['corporation_name'] }} - {{ kill['victim']['corporation_name'] }} - {% if kill['victim']['alliance_id'] != 0 %} - {{ kill['victim']['alliance_name'] }} - {{ kill['victim']['alliance_name'] }} - {% end %} - {{ kill['final_blow']['character_name'] }} - {{ kill['final_blow']['character_name'] }} - {{ kill['final_blow']['corporation_name'] }} - {{ kill['final_blow']['corporation_name'] }} - {% if kill['final_blow']['alliance_id'] != 0 %} - {{ kill['final_blow']['alliance_name'] }} - {{ kill['final_blow']['alliance_name'] }} - {% end %} -
-{% end %} +
{% end %} diff --git a/web/templates/kill.html b/web/templates/kill.html index bb286bc..112c2e8 100644 --- a/web/templates/kill.html +++ b/web/templates/kill.html @@ -1,21 +1,14 @@ {% extends "base.html" %} +{% block js %} + +{% end %} + {% block main %} -{{ kill['kill_time'] }}
-{{ kill['solarSystemName'] }} ({{ round(kill['security'], 1) }})
+
+
-{% for char in characters %} - {{ char ['typeName'] }} - {{ char['character_name'] }} - {{ char['character_name'] }} - {{ char['corporation_name'] }} - {{ char['corporation_name'] }} - {% if char['alliance_id'] != 0 %} - alliance - {{ char['alliance_name'] }} - {% end %} -
-{% end %} +
{% end %} diff --git a/web/templates/search.html b/web/templates/search.html index 03980af..d84c5da 100644 --- a/web/templates/search.html +++ b/web/templates/search.html @@ -1,12 +1,12 @@ {% extends "base.html" %} +{% block js %} + +{% end %} + {% block main %}

Corporations

-{% for corp in corps %} - - {{ corp['corporation_name'] }} - -{% end %} +
{% end %} -- cgit v1.2.3