Endpoints, Exceptions, and basic API obj with auth and getters

This commit is contained in:
Maël Kervella 2018-05-24 10:11:32 +00:00
parent c6baf34a15
commit 6d47993aee
3 changed files with 215 additions and 0 deletions

99
api.py Normal file
View file

@ -0,0 +1,99 @@
import requests
from requests.exceptions import HTTPError
import endpoints
import datetime
import exceptions
TIME_FOR_RENEW = 60
class Re2oAPI:
def __init__(self, hostname, username, password, use_tls=True):
self.use_tls = use_tls
self.hostname = hostname
self._username = username
self._password = password
self.token = self._obtain_token()
def _need_renew_token(self):
return self.token['expiration'] > datetime.datetime.utcnow() + \
datetime.timedelta(seconds=TIME_FOR_RENEW)
def _obtain_token(self):
response = requests.post(
self.get_url_for('token', forma=None),
data={'username': self._username, 'password': self._password}
)
if response.status_code == requests.codes.bad_request:
raise exceptions.InvalidCredentials()
response.raise_for_status()
response = response.json()
return {
'token': response['token'],
'expiration': datetime.datetime.strptime(
response['expiration'],
'%Y-%m-%dT%H:%M:%S.%fZ'
)
}
def get_token(self):
if self._need_renew_token():
self.token = self._obtain_token()
return self.token['token']
def get(self, url, *args, **kwargs):
headers = kwargs.pop('headers', {})
headers.update({
'Authorization': 'Token {}'.format(self.get_token())
})
response = requests.get(url, headers=headers, *args, **kwargs)
response.raise_for_status()
return response.json()
def post(self, url, *args, **kwargs):
headers = kwargs.pop('headers', {})
headers.update({
'Authorization': 'Token {}'.format(self.get_token())
})
response = requests.post(url, headers=headers, *args, **kwargs)
response.raise_for_status()
return response.json()
def get_url_for(self, name, forma='json', **kwargs):
url = '{proto}://{host}{endpoint}'.format(
proto=('https' if self.use_tls else 'http'),
host=self.hostname,
endpoint=endpoints.get_endpoint_for(name, **kwargs)
)
if forma:
url = '{url}.{forma}/'.format(url=url[:-1], forma=forma)
return url
def __getattr__(self, item):
if item.startswith('list_'):
def f(max_results=None, **kwargs):
response = self.get(
self.get_url_for('%s-list' % item[len('list_'):], **kwargs),
)
results = response['results']
while response['next'] is not None and \
(max_results is None or len(results) < max_results):
response = self.get(response['next'])
results += response['results']
return results[:max_results] if max_results else results
return f
elif item.startswith('count_'):
def f(**kwargs):
return self.get(
self.get_url_for('%s-list' % item[len('count_'):], **kwargs),
)['count']
return f
elif item.startswith('view_'):
def f(**kwargs):
return self.get(
self.get_url_for('%s-details' % item[len('view_'):], **kwargs),
)
return f
else:
raise AttributeError(item)

108
endpoints.py Normal file
View file

@ -0,0 +1,108 @@
import exceptions
urls = {
'root': '/api/',
'articles-list': '/api/cotisations/articles/',
'articles-details': '/api/cotisations/articles/{pk}/',
'banques-list': '/api/cotisations/banques/',
'banques-details': '/api/cotisations/banques/{pk}/',
'cotisations-list': '/api/cotisations/cotisations/',
'cotisations-details': '/api/cotisations/cotisations/{pk}/',
'factures-list': '/api/cotisations/factures/',
'factures-details': '/api/cotisations/factures/{pk}/',
'paiments-list': '/api/cotisations/paiements/',
'paiements-details': '/api/cotisations/paiements/{pk}/',
'ventes-list': '/api/cotisations/ventes/',
'ventes-details': '/api/cotisations/ventes/{pk}/',
'domains-list': '/api/machines/domains/',
'domains-details': '/api/machines/domains/{pk}/',
'extensions-list': '/api/machines/extensions/',
'extensions-details': '/api/machines/extensions/{pk}/',
'interfaces-list': '/api/machines/interfaces/',
'interfaces-details': '/api/machines/interfaces/{pk}/',
'iplists-list': '/api/machines/iplists/',
'iplists-details': '/api/machines/iplists/{pk}/',
'iptypes-list': '/api/machines/iptypes/',
'iptypes-details': '/api/machines/iptypes/{pk}/',
'ipv6lists-list': '/api/machines/ipv6lists/',
'ipv6lists-details': '/api/machines/ipv6lists/{pk}/',
'machines-list': '/api/machines/machines/',
'machines-details': '/api/machines/machines/{pk}/',
'machinetypes-list': '/api/machines/machinetypes/',
'machinetypes-details': '/api/machines/machinetypes/{pk}/',
'mx-list': '/api/machines/mx/',
'mx-details': '/api/machines/mx/{pk}/',
'nas-list': '/api/machines/nas/',
'nas-details': '/api/machines/nas/{pk}/',
'ns-list': '/api/machines/ns/',
'ns-details': '/api/machines/ns/{pk}/',
'ouvertureportlists-list': '/api/machines/ouvertureportlists/',
'ouvertureportlists-details': '/api/machines/ouvertureportlists/{pk}/',
'ouvertureports-list': '/api/machines/ouvertureports/',
'ouvertureports-details': '/api/machines/ouvertureports/{pk}/',
'servicelinks-list': '/api/machines/servicelinks/',
'servicelinks-details': '/api/machines/servicelinks/{pk}/',
'services-list': '/api/machines/services/',
'services-details': '/api/machines/services/{pk}/',
'soa-list': '/api/machines/soa/',
'soa-details': '/api/machines/soa/{pk}/',
'srv-list': '/api/machines/srv/',
'srv-details': '/api/machines/srv/{pk}/',
'txt-list': '/api/machines/txt/',
'txt-details': '/api/machines/txt/{pk}/',
'vlans-list': '/api/machines/vlans/',
'vlans-details': '/api/machines/vlans/{pk}',
'accesspoint-list': '/api/topologie/acesspoint/',
'accesspoint-details': '/api/topologie/acesspoint/{pk}/',
'building-list': '/api/topologie/building/',
'building-details': '/api/topologie/building/{pk}/',
'constructorswitch-list': '/api/topologie/constructorswitch/',
'contructorswitch-details': '/api/topologie/constructorswitch/{pk}/',
'modelswitch-list': '/api/topologie/modelswitch/',
'modelswitch-details': '/api/topologie/modelswitch/{pk}/',
'room-list': '/api/topologie/room/',
'room-details': '/api/topologie/room/{pk}/',
'stack-list': '/api/topologie/stack/',
'stack-details': '/api/topologie/stack/{pk}/',
'switch-list': '/api/topologie/switch/',
'switch-details': '/api/topologie/switch/{pk}/',
'switchbay-list': '/api/topologie/switchbay/',
'switchbay-details': '/api/topologie/switchbay/{pk}/',
'switchport-list': '/api/topologie/switchport/',
'switchport-details': '/api/topologie/switchport/{pk}/',
'adherents-list': '/api/users/adherents/',
'adherents-details': '/api/users/adherents/{pk}/',
'bans-list': '/api/users/bans/',
'bans-details': '/api/users/bans/{pk}/',
'clubs-list': '/api/users/clubs/',
'clubs-details': '/api/users/clubs/{pk}/',
'listrights-list': '/api/users/listrights/',
'listrights-details': '/api/users/listrights/{pk}/',
'schools-list': '/api/users/schools/',
'schools-details': '/api/users/schools/{pk}/',
'serviceusers-list': '/api/users/serviceusers/',
'serviceusers-details': '/api/users/serviceusers/{pk}/',
'shells-list': '/api/users/shells/',
'shells-details': '/api/users/shells/{pk}/',
'users-list': '/api/users/users/',
'users-details': '/api/users/users/{pk}/',
'whitelists-list': '/api/users/whitelists/',
'whitelists-details': '/api/users/whitelists/{pk}/',
'token': '/api/token-auth/',
}
def get_names():
return urls.keys()
def get_endpoint_for(name, **kwargs):
try:
url=urls[name]
except KeyError as e:
raise exceptions.URLNameNotExists(name)
else:
try:
return url.format_map(kwargs)
except KeyError as e:
raise exceptions.URLParameterMissing(e)

8
exceptions.py Normal file
View file

@ -0,0 +1,8 @@
class URLNameNotExists(ValueError):
pass
class URLParameterMissing(ValueError):
pass
class InvalidCredentials(ValueError):
pass