added ghapi app
added GithubAPIMiddleware added ghapi.api.GitHub API calls can be done via request.github.get/get_iter or GitHub().get/get_iter.
This commit is contained in:
parent
f11032202f
commit
fdeab7bee0
5 changed files with 125 additions and 0 deletions
1
ghapi/__init__.py
Normal file
1
ghapi/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
49
ghapi/api.py
Normal file
49
ghapi/api.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import urlparse
|
||||||
|
from django.http import QueryDict
|
||||||
|
from ghapi.linkheader import parse_link_value
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def get_next_page(response):
|
||||||
|
link = response.headers.get('link', None)
|
||||||
|
if not link:
|
||||||
|
return None
|
||||||
|
output = parse_link_value(link)
|
||||||
|
for url, info in output.items():
|
||||||
|
if info.get('rel', None) == 'next':
|
||||||
|
return QueryDict(urlparse.urlparse(url).query)['page']
|
||||||
|
return None
|
||||||
|
|
||||||
|
class GitHub(object):
|
||||||
|
def __init__(self, token=None):
|
||||||
|
headers = {}
|
||||||
|
if token:
|
||||||
|
headers['Authorization'] = 'token %s' % token
|
||||||
|
self.session = requests.session(headers=headers)
|
||||||
|
|
||||||
|
def get(self, path, params=None):
|
||||||
|
"""
|
||||||
|
Gets a resource, eg 'users/ojii'.
|
||||||
|
|
||||||
|
Returns tuple (jsondata, response)
|
||||||
|
"""
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
params['per_page'] = 100
|
||||||
|
response = self.session.get('https://api.github.com/%s' % path, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json, response
|
||||||
|
|
||||||
|
def get_iter(self, path, params=None):
|
||||||
|
"""
|
||||||
|
Returns an iterator over a resource, eg 'repos/divio/django-cms/watchers' that automatically handles
|
||||||
|
pagination.
|
||||||
|
"""
|
||||||
|
data, response = self.get(path, params)
|
||||||
|
for thing in data:
|
||||||
|
yield thing
|
||||||
|
next_page = get_next_page(response)
|
||||||
|
if next_page:
|
||||||
|
params['page'] = next_page
|
||||||
|
for thing in self.get(path, params):
|
||||||
|
yield thing
|
54
ghapi/linkheader.py
Normal file
54
ghapi/linkheader.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
|
|
||||||
|
TOKEN = r'(?:[^\(\)<>@,;:\\"/\[\]\?={} \t]+?)'
|
||||||
|
QUOTED_STRING = r'(?:"(?:\\"|[^"])*")'
|
||||||
|
PARAMETER = r'(?:%(TOKEN)s(?:=(?:%(TOKEN)s|%(QUOTED_STRING)s))?)' % locals()
|
||||||
|
LINK = r'<[^>]*>\s*(?:;\s*%(PARAMETER)s?\s*)*' % locals()
|
||||||
|
COMMA = r'(?:\s*(?:,\s*)+)'
|
||||||
|
LINK_SPLIT = r'%s(?=%s|\s*$)' % (LINK, COMMA)
|
||||||
|
|
||||||
|
def _unquotestring(instr):
|
||||||
|
if instr[0] == instr[-1] == '"':
|
||||||
|
instr = instr[1:-1]
|
||||||
|
instr = re.sub(r'\\(.)', r'\1', instr)
|
||||||
|
return instr
|
||||||
|
def _splitstring(instr, item, split):
|
||||||
|
if not instr:
|
||||||
|
return []
|
||||||
|
return [ h.strip() for h in re.findall(r'%s(?=%s|\s*$)' % (item, split), instr)]
|
||||||
|
|
||||||
|
link_splitter = re.compile(LINK_SPLIT)
|
||||||
|
|
||||||
|
def parse_link_value(instr):
|
||||||
|
"""
|
||||||
|
Given a link-value (i.e., after separating the header-value on commas),
|
||||||
|
return a dictionary whose keys are link URLs and values are dictionaries
|
||||||
|
of the parameters for their associated links.
|
||||||
|
|
||||||
|
Note that internationalised parameters (e.g., title*) are
|
||||||
|
NOT percent-decoded.
|
||||||
|
|
||||||
|
Also, only the last instance of a given parameter will be included.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
>>> parse_link_value('</foo>; rel="self"; title*=utf-8\'de\'letztes%20Kapitel')
|
||||||
|
{'/foo': {'title*': "utf-8'de'letztes%20Kapitel", 'rel': 'self'}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
out = {}
|
||||||
|
if not instr:
|
||||||
|
return out
|
||||||
|
for link in [h.strip() for h in link_splitter.findall(instr)]:
|
||||||
|
url, params = link.split(">", 1)
|
||||||
|
url = url[1:]
|
||||||
|
param_dict = {}
|
||||||
|
for param in _splitstring(params, PARAMETER, "\s*;\s*"):
|
||||||
|
try:
|
||||||
|
a, v = param.split("=", 1)
|
||||||
|
param_dict[a.lower()] = _unquotestring(v)
|
||||||
|
except ValueError:
|
||||||
|
param_dict[param.lower()] = None
|
||||||
|
out[url] = param_dict
|
||||||
|
return out
|
20
ghapi/middlewares.py
Normal file
20
ghapi/middlewares.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from django.utils.functional import SimpleLazyObject
|
||||||
|
from ghapi.api import GitHub
|
||||||
|
from social_auth.db.django_models import UserSocialAuth
|
||||||
|
|
||||||
|
|
||||||
|
def get_github(request):
|
||||||
|
if not request.user.is_authenticated():
|
||||||
|
return GitHub()
|
||||||
|
try:
|
||||||
|
social = UserSocialAuth.objects.get(provider='github', user_id=request.user.pk)
|
||||||
|
except UserSocialAuth.DoesNotExist:
|
||||||
|
return GitHub()
|
||||||
|
token = social.tokens.get('access_token', None)
|
||||||
|
return GitHub(token)
|
||||||
|
|
||||||
|
|
||||||
|
class GithubAPIMiddleware(object):
|
||||||
|
def process_request(self, request):
|
||||||
|
request.user = SimpleLazyObject(lambda : get_github(request))
|
|
@ -41,6 +41,7 @@ MIDDLEWARE_CLASSES = [
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'ghapi.middlewares.GithubAPIMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = [
|
TEMPLATE_CONTEXT_PROCESSORS = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue