Initial import

This commit is contained in:
2011-11-02 13:52:41 +00:00
commit 233c2946de
8 changed files with 302 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
env/
test.py
build/
*.pyc

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
-e git+https://github.com/nikdoof/eveapi.git#egg=eveapi
ordereddict
jinja2
argparse

64
scripts/evestandings Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python
import sys
import os
from argparse import ArgumentParser
from ConfigParser import ConfigParser
import standings
def load_config(file='~/.evestandings.conf'):
config = ConfigParser()
file = os.path.expanduser(file)
if os.path.exists(file):
config.read(file)
outconfig = object()
for name, val in config.items('standings'):
setattr(outconfig, name, val)
return outconfig
else:
return {}
def output_html(keyid, vcode, character, type):
sys.stdout.write(Standings(keyid, vcode, character, type=type)._get_html())
if __name__ == '__main__':
parser = ArgumentParser(prog='EVEStandings', description='Outputs a EVE corporation/alliance standings to a HTML page')
parser.add_argument('-k', '--keyid', help='Key ID of the API key')
parser.add_argument('-v', '--vcode', help='vCode of the API key')
parser.add_argument('-c', '--character', help='Character whos corporation you wish to output')
parser.add_argument('-t', '--type', help='Type of standings list, either corp or alliance')
parser.add_argument('-C', '--config', help='Path to your configuration file')
parser.add_argument('-f', '--output', help='Output the resulting HTML to a file')
parser.add_argument('--template', help='Location of a customized template to use instead of the default')
parser.add_argument('--version', action='version', version='%(prog)s ' + standings.__version__)
ns = parser.parse_args()
#
if 'keyid' in ns or 'vcode' in ns:
conf = ns
else:
if 'config' in ns:
conf = load_config(ns['config'])
else:
conf = load_config()
if not conf.keyid or not conf.vcode:
sys.stderr.write('Key ID or vCode is missing, please provide both on the command line or in the config file\n')
parser.print_help()
sys.exit(os.EX_USAGE)
print ns
obj = standings.Standings(conf.keyid, conf.vcode, conf.character)
html = obj._get_html(conf.template)
if conf.output:
f = open(os.path.expanduser(conf.output), 'w')
f.write(html)
f.close()
else:
sys.stdout.write(html)
sys.exit(0)

21
setup.py Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env python
from distutils.core import setup
from standings import __version__
setup(name = "standings",
version = __version__,
description = "EVE API Standings Page Generator",
author = "Andrew Willaims",
author_email = "andy@tensixtyone.com",
url = "https://dev.pleaseignore.com/",
keywords = "eveapi",
packages = ['standings',],
scripts = ['scripts/evestandings'],
package_data={'standings': ['templates/*.html']},
classifiers = [
'License :: OSI Approved :: BSD License',
'Development Status :: 3 - Alpha',
]
)

94
standings/__init__.py Normal file
View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
import sys
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
from eveapi import EVEAPIConnection, Error
from jinja2 import Environment, PackageLoader
from standings.cache import DbCacheHandler
__version__ = '0.1'
STANDINGS_ALLIANCE = 0
STANDINGS_CORPORATION = 1
class Standings:
"""
Grabs the latest Standings from the EVE API and outputs them into
a nice template format
"""
def __init__(self, keyid, vcode, characterid, dbpath='/tmp/standingscache.sqlite3', type=STANDINGS_ALLIANCE):
self.eveapi = EVEAPIConnection(cacheHandler=DbCacheHandler(dbpath)).auth(keyID=keyid, vCode=vcode)
self.character = characterid
self.standings_type = type
@property
def _get_alliance_id_list(self):
if not hasattr(self, '_allianceids'):
self._allianceids = set([x.allianceID for x in EVEAPIConnection().eve.AllianceList().alliances])
return self._allianceids
def _check_if_corp(self, corpid):
try:
res = EVEAPIConnection().corp.CorporationSheet(corporationID=corpid)
except Error:
return False
return True
def _get_standings(self):
res = self.eveapi.corp.ContactList(characterID=self.character)
standings = OrderedDict()
for x in ['excellent', 'good', 'neutral', 'bad', 'terrible']: standings[x] = []
def parse_list(list, output):
for row in list:
level = float(row['standing'])
if level > 5 and level <= 10:
type = 'excellent'
elif level > 0 and level <= 5:
type = 'good'
elif level < 0 and level >= -5:
type = 'bad'
elif level < -5 and level >= -10:
type = 'terrible'
else:
# Neutral?
type = 'neutral'
if int(row['contactID']) in self._get_alliance_id_list:
rowtype = 'alli'
elif self._check_if_corp(int(row['contactID'])):
rowtype = 'corp'
else:
rowtype = 'char'
output[type].append((rowtype, row['contactID'], row['contactName'], row['standing']))
# Order standings for each group
for x in ['excellent', 'good', 'neutral', 'bad', 'terrible']:
standings[x] = sorted(standings[x], key=lambda v: -int(v[3]))
if self.standings_type == STANDINGS_ALLIANCE:
parse_list(res.allianceContactList, standings)
else:
parse_list(res.corporateContactList, standings)
return standings
def _get_name(self):
res = self.eveapi.corp.CorporationSheet()
if hasattr(res, 'allianceName'): return res.allianceName
return res.corporationName
def _get_html(self, template='standings_list.html'):
if not template: template = 'standings_list.html'
env = Environment(loader=PackageLoader('standings', 'templates'))
template = env.get_template(template)
return template.render(standings=self._get_standings(), name=self._get_name())

83
standings/cache.py Normal file
View File

@@ -0,0 +1,83 @@
from hashlib import sha1
import logging
import sqlite3
SQLITE_PATH = '/tmp/eveapicache.sqlite3'
class DbCacheHandler:
"""
Database backed cache handler for Entity's eveapi module
"""
def __init__(self, conn=SQLITE_PATH):
self._conn_url = conn
@property
def log(self):
if not hasattr(self, '_log'):
self._log = logging.getLogger(self.__class__.__name__)
return self._log
@property
def conn(self):
if not hasattr(self, '_conn') or not self._conn:
self._conn = sqlite3.connect(self._conn_url)
self.setup()
return self._conn
@property
def cursor(self):
if not hasattr(self, '_cursor') or not self._cursor:
self._cursor = self.conn.cursor()
return self._cursor
def setup(self):
if not hasattr(self, '_setupchecked'):
self.cursor.execute('CREATE TABLE IF NOT EXISTS api_cache(docid TEXT PRIMARY KEY, xml TEXT, cacheduntil TEXT)')
self._setupchecked = True
def disconnect(self):
if hasattr(self, '_cursor'):
self._cursor.close()
self._cursor = None
if hasattr(self, '_conn'):
self._conn.close()
self._conn = None
@staticmethod
def _gen_docid(host, path, params):
return sha1("%s%s?%s" % (host, path, params)).hexdigest()
def retrieve(self, host, path, params):
docid = self._gen_docid(host, path, params)
self.log.debug("Retrieving document: %s" % docid)
try:
self.cursor.execute("SELECT xml FROM api_cache WHERE docid = ? and datetime(cacheduntil, 'unixepoch') >= current_timestamp", (docid,))
res = self.cursor.fetchone()
self.disconnect()
except sqlite3.Error as e:
self.log.error("Error retrieving document: %s", e.args[0])
else:
if res:
self.log.debug("Found %s documents for ID %s" % (len(res), docid))
return res[0]
return None
def store(self, host, path, params, doc, obj):
docid = self._gen_docid(host, path, params)
self.log.debug("Storing document: %s (%s)" % (docid, path))
try:
self.cursor.execute('REPLACE INTO api_cache (docid, xml, cacheduntil) VALUES (?, ?, ?)', (docid, doc, obj.cachedUntil))
self.conn.commit()
self.disconnect()
except sqlite3.Error as e:
self.log.error("Error storing document: %s", e.args[0])
def purge_stale(self):
self.log.info("Purging stale cached documents")
try:
self.cursor.execute("DELETE FROM api_cache WHERE datetime(cacheduntil, 'unixepoch') >= current_timestamp")
self.conn.commit()
self.disconnect()
except sqlite3.Error as e:
self.log.error("Error purging document cache: %s", e.args[0])

View File

@@ -0,0 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
{% block head %}<title>{% block title %}{% endblock %}</title>{% endblock %}
</head>
<body>
<div class="container">
<div class="content">
{% block content %}<p>It seems something has gone wrong, please contact a admin</p>{% endblock %}
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block head %}
<title>{{ name }} Standings</title>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css">
{% endblock %}
{% block content %}
{% for type in standings %}
<div class="row" id="{{ type }}">
<p><h1 class="muted">{{ type }}</h1></p>
<p>
{% for type, id, entname, standing in standings[type] %}
<img src="{% if type == 'corp' %}http://image.eveonline.com/Corporation/{{ id }}_64.png{% endif %}{% if type == 'alli' %}http://image.eveonline.com/Alliance/{{ id }}_64.png{% endif %}{% if type == 'char' %}http://image.eveonline.com/Character/{{ id }}_64.jpg{% endif %}" title="{{ entname }} ({{ standing }})"></li>
{% endfor %}
</p>
</div>
{% endfor %}
{% endblock %}