Reorganise the file structure into a project tree

This commit is contained in:
2011-03-11 12:58:50 +00:00
parent 58b1691638
commit 3686aa7523
226 changed files with 7 additions and 5 deletions

0
app/api/__init__.py Normal file
View File

15
app/api/admin.py Normal file
View File

@@ -0,0 +1,15 @@
from django.contrib import admin
from api.models import AuthAPIKey, AuthAPILog
class AuthAPIKeyAdmin(admin.ModelAdmin):
list_display = ('key', 'name', 'url', 'active')
search_fields = ['name']
class AuthAPILogAdmin(admin.ModelAdmin):
list_display = ('key', 'url', 'access_datetime')
admin.site.register(AuthAPIKey, AuthAPIKeyAdmin)
admin.site.register(AuthAPILog, AuthAPILogAdmin)

27
app/api/auth.py Normal file
View File

@@ -0,0 +1,27 @@
from django.http import HttpResponseForbidden
from django.contrib.auth.models import AnonymousUser
from api.models import AuthAPIKey
class APIKeyAuthentication(object):
def is_authenticated(self, request):
params = {}
for key, value in request.GET.items():
params[key.lower()] = value
if 'apikey' in params:
try:
keyobj = AuthAPIKey.objects.get(key=params['apikey'])
except:
keyobj = None
if keyobj and keyobj.active:
request.user = AnonymousUser()
return True
return False
def challenge(self):
return HttpResponseForbidden('Access Denied, use a API Key')

View File

@@ -0,0 +1,2 @@
from v1 import *
from v2 import *

250
app/api/handlers/v1.py Normal file
View File

@@ -0,0 +1,250 @@
import re
from datetime import datetime
from piston.handler import BaseHandler
from piston.utils import rc, throttle
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from api.models import AuthAPIKey, AuthAPILog
from eve_proxy.models import CachedDocument
from eve_proxy.exceptions import *
from eve_api.models import EVEAccount, EVEPlayerCharacter
from sso.models import ServiceAccount, Service
from hr.models import Blacklist
from settings import FULL_API_USER_ID
from settings import FULL_API_CHARACTER_ID
from xml.dom import minidom
class UserHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request):
if 'userid' in request.GET:
try:
u = User.objects.get(id=request.GET['userid'])
except (User.DoesNotExist, ValueError):
return {'auth': 'missing', 'missing': 'userid'}
elif 'user' in request.GET:
try:
u = User.objects.get(username=request.GET['user'])
except User.DoesNotExist:
return {'auth': 'missing', 'missing': 'username'}
elif 'serviceuid' in request.GET:
try:
u = ServiceAccount.objects.get(service_uid=request.GET['serviceuid']).user
except ServiceAccount.DoesNotExist:
return {'auth': 'missing', 'missing': 'ServiceAccount'}
elif 'apiuserid' in request.GET:
try:
u = EVEAccount.objects.get(api_user_id=request.GET['apiuserid']).user
except EVEAccount.DoesNotExist:
return {'auth': 'missing', 'missing': 'apiuserid'}
chars = []
for a in u.eveaccount_set.all():
chars.extend(a.characters.all())
d = {'id': u.id, 'username': u.username, 'email': u.email,
'serviceaccounts': u.serviceaccount_set.all(), 'characters': chars,
'groups': u.groups.all(), 'staff': u.is_staff, 'superuser': u.is_superuser}
return d
class LoginHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request):
u = None
if request.GET.get('user', None):
try:
u = User.objects.get(username=request.GET['user'])
except User.DoesNotExist:
return {'auth': 'missing', 'missing': 'Username'}
if u:
if request.GET.get('pass', None) and request.GET['pass'] == u.get_profile().api_service_password:
return {'auth': 'ok', 'id': u.id, 'username': u.username,
'email': u.email, 'groups': u.groups.all(),
'staff': u.is_staff, 'superuser': u.is_superuser}
else:
return {'auth': 'failed'}
return {'auth': 'missing', 'missing': 'all'}
class EveAPIHandler(BaseHandler):
allowed_methods = ('GET')
exclude = ('api_key')
def read(self, request):
if request.GET.get('id', None):
s = get_object_or_404(EVEAccount, pk=id)
elif request.GET.get('userid', None):
s = EVEAccount.objects.filter(user=request.GET['userid'])
elif request.GET.get('corpid', None):
s = EVEAccount.objects.filter(characters__corporation__id=request.GET['corpid'])
elif request.GET.get('allianceid', None):
s = EVEAccount.objects.filter(characters__corporation__alliance__id=request.GET['allianceid'])
return {'keys': s.values('id', 'user_id', 'api_status', 'api_last_updated')}
class EveAPIProxyHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request):
url_path = request.META['PATH_INFO'].replace(reverse('api-eveapiproxy'), "/")
params = {}
for key, value in request.GET.items():
params[key.lower()] = value
if 'userid' in params:
obj = get_object_or_404(EVEAccount, pk=params['userid'])
params['apikey'] = obj.api_key
try:
cached_doc = CachedDocument.objects.api_query(url_path, params)
except DocumentRetrievalError, exc:
return HttpResponse(exc, status=500)
else:
return HttpResponse(cached_doc.body)
class OpTimerHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request, id=None):
obj = get_object_or_404(EVEAccount, id=FULL_API_USER_ID)
params = {'userID': obj.id, 'apiKey': obj.api_key, 'characterID': FULL_API_CHARACTER_ID}
error_doc = {'ops': [{'startsIn': -1, 'eventID': 0, 'ownerName': '', 'eventDate': '', 'eventTitle': '<div style="text-align:center">The EVE API calendar is unavailable</div>', 'duration': 0, 'isImportant': 0, 'eventText': 'Fuck CCP tbqh imho srsly', 'endsIn':-1, 'forumLink': ''}]}
try:
cached_doc = CachedDocument.objects.api_query('/char/UpcomingCalendarEvents.xml.aspx', params)
except DocumentRetrievalError:
return error_doc
dom = minidom.parseString(cached_doc.body.encode('utf-8'))
if dom.getElementsByTagName('error'):
error_doc['raw_xml'] = cached_doc.body
return error_doc
events = []
for node in dom.getElementsByTagName('rowset')[0].childNodes:
if node.nodeType == 1:
ownerID = node.getAttribute('ownerID')
if ownerID != '1':
date = node.getAttribute('eventDate')
dt = datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
now = datetime.utcnow()
startsIn = int(dt.strftime('%s')) - int(now.strftime('%s'))
duration = int(node.getAttribute('duration'))
fid = re.search('topic=[\d]+', node.getAttribute('eventText'))
if fid:
forumlink = 'http://forum.pleaseignore.com/index.php?%s' % fid.group(0)
else:
forumlink = ''
#In case people forget to set a duration, we'll give a default of 1 hour
if duration == 0:
duration = 60
endsIn = startsIn + (duration * 60)
if startsIn < 0:
startsIn = 0
if endsIn > 0:
event = {
'startsIn': startsIn,
'eventID': node.getAttribute('eventID'),
'ownerName': node.getAttribute('ownerName'),
'eventDate': date,
'eventTitle': node.getAttribute('eventTitle'),
'duration': duration,
'isImportant': node.getAttribute('importance'),
'eventText': node.getAttribute('eventText'),
'endsIn':endsIn,
'forumLink': forumlink}
events.append(event)
if len(events) == 0:
return {'ops':[{
'startsIn': -1,
'eventID': 0,
'ownerName': '',
'eventDate': '',
'eventTitle': '<div style="text-align:center">No ops are currently scheduled</div>',
'duration': 0,
'isImportant': 0,
'eventText': 'Add ops using EVE-Gate or the in-game calendar',
'endsIn':-1,
'forumLink': ''}]}
else:
return {'ops': events, 'doc_time': cached_doc.time_retrieved, 'cache_until': cached_doc.cached_until, 'current_time': datetime.utcnow() }
class BlacklistHandler(BaseHandler):
model = Blacklist
allowed_methods = ('GET')
fields = ('type', 'value', 'source', ('name', 'ticker'), 'created_date', 'expiry_date', 'reason')
def read(self, request):
if request.GET.get('value'):
obj = Blacklist.objects.select_related('blacklistsource').filter(value__icontains=request.GET.get('value'))
if obj.count() and request.GET.get('type'):
obj = obj.filter(type=request.GET.get('type'))
else:
obj = []
return obj
class CharacterHandler(BaseHandler):
allowed_methods = ('GET')
fields = ('id', 'name', ('corporation', ('id', 'name', ('alliance', ('id', 'name')))), 'corporation_date', 'balance', 'total_sp', 'security_status', 'director', 'skillset')
@classmethod
def skillset(cls, instance):
return instance.eveplayercharacterskill_set.all().values('skill__id', 'skill__name', 'level', 'skillpoints')
def read(self, request):
s = []
if request.GET.get('id', None):
s = get_object_or_404(EVEPlayerCharacter, pk=id)
elif request.GET.get('corpid', None):
s = EVEPlayerCharacter.objects.filter(corporation__id=request.GET['corpid'])
elif request.GET.get('allianceid', None):
s = EVEPlayerCharacter.objects.filter(corporation__alliance__id=request.GET['allianceid'])
return s
class AnnounceHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request):
sid = request.GET.get('sid', None)
to = request.GET.getlist('to')
message = request.GET.get('message', None)
subject = request.GET.get('subject', None)
if sid and to and message:
srv = get_object_or_404(Service, pk=sid)
if not srv.api == 'sso.services.jabber':
return {'result': 'invalid'}
api = srv.api_class
return {'result': api.announce(api.settings['jabber_server'], message, subject, groups=to)}
return {'result': 'invalid'}

113
app/api/handlers/v2.py Normal file
View File

@@ -0,0 +1,113 @@
from django.contrib.auth.models import User
from piston.handler import BaseHandler
from piston.utils import rc
from eve_api.models import EVEAccount, EVEPlayerCharacter
from eve_proxy.models import CachedDocument
class V2AuthenticationHandler(BaseHandler):
"""
Authenticate a user against the Auth user DB.
Provides back a session allowing further access
"""
allowed_methods = ('GET')
def read(self, request):
"""
Validates login details for the provided user as
long as 'username' and 'password' are provided.
"""
username = request.GET.get('username', None)
password = request.GET.get('password', None)
if not username or not password:
return rc.BAD_REQUEST
try:
user = User.object.get(username=username)
except User.DoesNotExist:
resp = rc.NOT_FOUND
resp.write({'auth': 'notfound'})
return resp
if password and password == user.get_profile().api_service_password:
return {'userid': user.id,
'username': user.username,
'email': user.email,
'groups': user.groups.all().values('id', 'name'),
'staff': user.is_staff,
'superuser': user.is_superuser}
resp = rc.FORBIDDEN
resp.write({'auth': 'failed'})
return resp
class V2EveAPIProxyHandler(BaseHandler):
"""
Provides a proxy handler to the EVE API using 'eve_proxy'
"""
allowed_methods = ('GET')
def read(self, request):
"""
Acts as a EVE API proxy, all params are passed to the
API, for the exception of 'apikey' which is dervived from the
stored information and 'userid'
'apikey' field should be populated with the Auth API key.
"""
url_path = request.META['PATH_INFO'].url_path.replace(reverse('v2-api-eveapiproxy'), "/")
params = {}
for key, value in request.GET.items():
params[key.lower()] = value
try:
userid = request.GET.get('userid', None)
obj = EVEAccount.objects.get(api_user_id=userid)
params['apikey'] = obj.api_key
except EVEAccount.DoesNotExist:
pass
try:
cached_doc = CachedDocument.objects.api_query(url_path, params)
except DocumentRetrievalError:
return HttpResponse(status=500)
else:
return HttpResponse(cached_doc.body)
class V2UserHandler(BaseHandler):
allowed_methods = ('GET')
def read(self, request, userid):
try:
u = User.objects.get(id=userid)
except (User.DoesNotExist, ValueError):
resp = rc.NOT_FOUND
charlist = []
for acc in u.eveaccount_set.all():
for char in acc.characters.all().select_related('characters').values('id', 'name', 'corporation', 'corporation_date', 'corporation__name'):
d = dict(char)
d['eveaccount'] = acc.id
charlist.append(d)
d = {'id': u.id,
'username': u.username,
'email': u.email,
'eveaccounts': u.eveaccount_set.all().values('api_user_id', 'description', 'api_status', 'api_keytype'),
'serviceaccounts': u.serviceaccount_set.all().values('service', 'service__name', 'service__api', 'service_uid'),
'characters': charlist,
'groups': u.groups.all().values('id', 'name'),
'staff': u.is_staff,
'superuser': u.is_superuser}
return d

View File

@@ -0,0 +1,58 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'AuthAPIKey'
db.create_table('api_authapikey', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
('url', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
('active', self.gf('django.db.models.fields.BooleanField')(default=True, blank=True)),
('key', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)),
))
db.send_create_signal('api', ['AuthAPIKey'])
# Adding model 'AuthAPILog'
db.create_table('api_authapilog', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('access_datetime', self.gf('django.db.models.fields.DateTimeField')()),
('key', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['api.AuthAPIKey'])),
('url', self.gf('django.db.models.fields.CharField')(max_length=200)),
))
db.send_create_signal('api', ['AuthAPILog'])
def backwards(self, orm):
# Deleting model 'AuthAPIKey'
db.delete_table('api_authapikey')
# Deleting model 'AuthAPILog'
db.delete_table('api_authapilog')
models = {
'api.authapikey': {
'Meta': {'object_name': 'AuthAPIKey'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
},
'api.authapilog': {
'Meta': {'object_name': 'AuthAPILog'},
'access_datetime': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['api.AuthAPIKey']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200'})
}
}
complete_apps = ['api']

View File

37
app/api/models.py Normal file
View File

@@ -0,0 +1,37 @@
import uuid
from django.db import models
class AuthAPIKey(models.Model):
""" Auth API Key storage model """
name = models.CharField("Service Name", max_length=200)
url = models.CharField("Service URL", max_length=200, blank=True)
active = models.BooleanField(default=True)
key = models.CharField("API Key", max_length=200, blank=True)
def save(self, *args, **kwargs):
if not self.key or self.key == '':
self.key = uuid.uuid4()
models.Model.save(self, *args, **kwargs)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'API Key'
verbose_name_plural = "API Keys"
class AuthAPILog(models.Model):
""" Auth API Access Log """
access_datetime = models.DateTimeField("Date/Time Accessed")
key = models.ForeignKey(AuthAPIKey)
url = models.CharField("Accessed URL", max_length=200)
class Meta:
ordering = ['access_datetime']
verbose_name = 'API Access Log'
verbose_name_plural = "API Access Logs"

41
app/api/urls.py Executable file
View File

@@ -0,0 +1,41 @@
from django.conf.urls.defaults import *
from piston.resource import Resource
from piston.authentication import NoAuthentication
from api.auth import APIKeyAuthentication
from api.handlers import *
noauth = {'authentication': NoAuthentication() }
apikeyauth = {'authentication': APIKeyAuthentication() }
# v1 APIs
user_resource = Resource(handler=UserHandler, **apikeyauth)
login_resource = Resource(handler=LoginHandler, **noauth)
eveapi_resource = Resource(handler=EveAPIHandler, **apikeyauth)
eveapiproxy_resource = Resource(handler=EveAPIProxyHandler, **apikeyauth)
optimer_resource = Resource(handler=OpTimerHandler, **apikeyauth)
blacklist_resource = Resource(handler=BlacklistHandler, **apikeyauth)
characters_resource = Resource(handler=CharacterHandler, **apikeyauth)
announce_resource = Resource(handler=AnnounceHandler, **apikeyauth)
urlpatterns = patterns('',
url(r'^user/$', user_resource),
url(r'^login/$', login_resource),
url(r'^eveapi/$', eveapi_resource),
url(r'^eveapi/', eveapiproxy_resource, name='api-eveapiproxy'),
url(r'^character/$', characters_resource),
url(r'^optimer/$', optimer_resource),
url(r'^blacklist/$', blacklist_resource),
url(r'^announce/$', announce_resource),
)
# v2 APIs
v2_authenticate_resource = Resource(handler=V2AuthenticationHandler, **noauth)
v2_eveapiproxy_resource = Resource(handler=V2EveAPIProxyHandler, **apikeyauth)
v2_user_resource = Resource(handler=V2UserHandler, **apikeyauth)
urlpatterns += patterns('',
url(r'^v2/authenticate/$', v2_authenticate_resource),
url(r'^v2/proxy/', v2_eveapiproxy_resource, name='v2-api-eveapiproxy'),
url(r'^v2/user/(?P<userid>\d+)/$', v2_user_resource),
)

5
app/api/views.py Normal file
View File

@@ -0,0 +1,5 @@
from django.http import HttpResponse
def oauth_callback(request, other):
return HttpResponse('Fake callback view.')