mirror of
https://github.com/nikdoof/test-auth.git
synced 2025-12-22 14:19:28 +00:00
OAuth Support
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from api.models import AuthAPIKey, AuthAPILog
|
||||
|
||||
from piston.models import Consumer, Token
|
||||
|
||||
class AuthAPIKeyAdmin(admin.ModelAdmin):
|
||||
list_display = ('key', 'name', 'url', 'active')
|
||||
@@ -18,3 +18,5 @@ class AuthAPILogAdmin(admin.ModelAdmin):
|
||||
|
||||
admin.site.register(AuthAPIKey, AuthAPIKeyAdmin)
|
||||
admin.site.register(AuthAPILog, AuthAPILogAdmin)
|
||||
admin.site.register(Consumer, admin.ModelAdmin)
|
||||
admin.site.register(Token, admin.ModelAdmin)
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from v1 import *
|
||||
from v2 import *
|
||||
from oauth import *
|
||||
|
||||
120
app/api/handlers/oauth.py
Normal file
120
app/api/handlers/oauth.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import re
|
||||
from datetime import datetime
|
||||
from xml.dom import minidom
|
||||
from operator import itemgetter
|
||||
|
||||
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 django.conf import settings
|
||||
|
||||
from piston.handler import BaseHandler
|
||||
from piston.utils import rc, throttle
|
||||
|
||||
from api.models import AuthAPIKey, AuthAPILog
|
||||
|
||||
from eve_proxy.models import CachedDocument
|
||||
from eve_proxy.exceptions import *
|
||||
from eve_api.app_defines import *
|
||||
from eve_api.models import EVEAccount, EVEPlayerCharacter
|
||||
|
||||
|
||||
class OAuthEveAPIHandler(BaseHandler):
|
||||
allowed_methods = ('GET')
|
||||
exclude = ('api_key')
|
||||
|
||||
def read(self, request):
|
||||
if request.user:
|
||||
s = EVEAccount.objects.filter(user=request.user)
|
||||
return {'keys': s.values('api_user_id', 'user_id', 'api_status', 'api_last_updated')}
|
||||
|
||||
|
||||
class OAuthOpTimerHandler(BaseHandler):
|
||||
allowed_methods = ('GET')
|
||||
|
||||
def read(self, request, id=None):
|
||||
|
||||
objs = EVEAccount.objects.filter(user=request.user, api_keytype=API_KEYTYPE_FULL)
|
||||
|
||||
if not objs.count():
|
||||
objs = [get_object_or_404(EVEAccount, pk=settings.FULL_API_USER_ID)]
|
||||
|
||||
events = []
|
||||
for obj in objs:
|
||||
params = {'userID': obj.pk, 'apiKey': obj.api_key, 'characterID': settings.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, timeout=10, service="Optimer")
|
||||
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
|
||||
|
||||
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:
|
||||
events.sort(key=itemgetter('startsIn'))
|
||||
return {'ops': events, 'doc_time': cached_doc.time_retrieved, 'cache_until': cached_doc.cached_until, 'current_time': datetime.utcnow() }
|
||||
|
||||
|
||||
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):
|
||||
return EVEPlayerCharacter.objects.filter(eveaccount__user=request.user)
|
||||
23
app/api/templates/api/view_tokens.html
Normal file
23
app/api/templates/api/view_tokens.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Application Access{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>Application Access</h1>
|
||||
|
||||
<p>This is the list of external applications that can access your data stored on Auth, this includes any EVE API data and also any linked information (Reddit accounts, service accounts).</p>
|
||||
|
||||
{% if tokens %}
|
||||
<table>
|
||||
<tr><th>Application</th><th>Granted Date/Time</th><th>Action</th></tr>
|
||||
{% for token in tokens %}
|
||||
<tr>
|
||||
<tr><td>{{ token.consumer.name }}</td><td></td><td><a href="{% url oauth-revoke-token token.key %}">Revoke</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p><b>You have not granted any applications access to your data</b></p>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.conf.urls.defaults import *
|
||||
from piston.authentication import NoAuthentication
|
||||
from piston.authentication import NoAuthentication, OAuthAuthentication
|
||||
|
||||
from api.resource import SentryResource as Resource
|
||||
from api.auth import APIKeyAuthentication
|
||||
@@ -7,6 +7,7 @@ from api.handlers import *
|
||||
|
||||
noauth = {'authentication': NoAuthentication() }
|
||||
apikeyauth = {'authentication': APIKeyAuthentication() }
|
||||
oauth = {'authentication': OAuthAuthentication() }
|
||||
|
||||
# v1 APIs
|
||||
user_resource = Resource(handler=UserHandler, **apikeyauth)
|
||||
@@ -19,17 +20,6 @@ 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),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('',
|
||||
url(r'^1.0/user/$', user_resource),
|
||||
url(r'^1.0/login/$', login_resource),
|
||||
url(r'^1.0/eveapi/$', eveapi_resource),
|
||||
@@ -50,3 +40,23 @@ urlpatterns += patterns('',
|
||||
url(r'^2.0/proxy/', v2_eveapiproxy_resource, name='v2-api-eveapiproxy'),
|
||||
url(r'^2.0/user/(?P<userid>\d+)/$', v2_user_resource, name='v2-api-user'),
|
||||
)
|
||||
|
||||
# OAuth
|
||||
urlpatterns += patterns('piston.authentication',
|
||||
url(r'^oauth/request_token/$','oauth_request_token'),
|
||||
url(r'^oauth/authorize/$','oauth_user_auth'),
|
||||
url(r'^oauth/access_token/$','oauth_access_token'),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('api.views',
|
||||
url(r'^oauth/tokens/$', 'oauth_list_tokens', name='oauth-list-tokens'),
|
||||
url(r'^oauth/tokens/(?P<key>.*)$', 'oauth_revoke_token', name='oauth-revoke-token'),
|
||||
)
|
||||
|
||||
oauth_optimer_resource = Resource(handler=OAuthOpTimerHandler, **oauth)
|
||||
|
||||
# API
|
||||
urlpatterns += patterns('',
|
||||
url(r'^oauth/optimer/$', oauth_optimer_resource),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
|
||||
from piston import forms
|
||||
from piston.models import Token
|
||||
|
||||
def oauth_callback_view(request, other):
|
||||
return HttpResponse("The application you allowed access to didn't request a callback, thats odd and should be fixed")
|
||||
|
||||
|
||||
def oauth_callback(request, other):
|
||||
return HttpResponse('Fake callback view.')
|
||||
@login_required
|
||||
def oauth_auth_view(request, token, callback, params):
|
||||
form = forms.OAuthAuthenticationForm(initial={
|
||||
'oauth_token': token.key,
|
||||
'oauth_callback': token.get_callback_url() or callback,
|
||||
})
|
||||
|
||||
return render_to_response('piston/authorize_token.html',
|
||||
{ 'form': form, 'consumer': token.consumer, 'user': token.user, 'request': request }, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def oauth_list_tokens(request):
|
||||
# List all Access tokens
|
||||
tokens = Token.objects.filter(token_type=Token.ACCESS)
|
||||
return render_to_response('api/view_tokens.html', { 'tokens': tokens, 'request': request }, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def oauth_revoke_token(request, key):
|
||||
token = get_object_or_404(Token, key=key)
|
||||
if token.user == request.user:
|
||||
token.delete()
|
||||
messages.success(request, "Access for %s has been revoked" % token.consumer.name, fail_silently=True)
|
||||
|
||||
return redirect(oauth_list_tokens)
|
||||
|
||||
Reference in New Issue
Block a user