Commit c3277c2e authored by Maël Kervella's avatar Maël Kervella

Do not use endpoint's names

Use the URL structure directly to build the requests directly
The mapping name <-> endpoint is no longer used
See discusion in #1 for details
parent 2deb99c5
......@@ -174,7 +174,7 @@ class Re2oAPIClient:
# Perform the authentication request
response = requests.post(
self.get_url_for('token'),
self.get_url_for('token-auth'),
data={'username': self._username, 'password': self._password}
)
self.log.debug("Response code: "+str(response.status_code))
......@@ -423,11 +423,11 @@ class Re2oAPIClient:
"""
return self._request('put', *args, **kwargs)
def get_url_for(self, name, **kwargs):
def get_url_for(self, endpoint):
"""Retrieve the complete URL to use for a given endpoint's name.
Args:
name: The name of the endpoint to look for.
endpoint: The path of the endpoint.
**kwargs: A dictionnary with the parameter to use to build the
URL (using .format() syntax)
......@@ -438,23 +438,24 @@ class Re2oAPIClient:
re2oapi.exception.NameNotExists: The provided name does not
correspond to any endpoint.
"""
return '{proto}://{host}{endpoint}'.format(
return '{proto}://{host}/{namespace}/{endpoint}'.format(
proto=('https' if self.use_tls else 'http'),
host=self.hostname,
endpoint=endpoints.get_endpoint_for(name, self.log, **kwargs)
namespace='api',
endpoint=endpoint
)
def _list_for(self, obj_name, max_results=None, params={}, **kwargs):
"""List all '{obj_name}' objects on the server.
def list(self, endpoint, max_results=None, params={}):
"""List all objects on the server that corresponds to the given
endpoint. The endpoint must be valid for listing objects.
Args:
endpoint: The path of the endpoint.
max_results: A limit on the number of result to return
params: See `requests.get` params.
**kwargs: A dictionnary used to defines the required parameters
in order to build the URL (using `.format()`).
Returns:
The list of all the {obj_name} objects serialized
as returned by the API.
The list of all the objects serialized as returned by the API.
Raises:
requests.exceptions.RequestException: An error occured while
......@@ -462,18 +463,19 @@ class Re2oAPIClient:
exceptions.PermissionDenied: The user does not have the right
to perform this request.
"""
self.log.info("Starting listing {} objects".format(obj_name))
self.log.info("Starting listing objects under '{}'"
.format(endpoint))
self.log.debug("max_results = "+str(max_results))
# For optimization, list all results in one page unless the user
# is forcing the use of a different `page_size`.
if not 'page_size' in params.keys():
self.log.debug("Forcing 'page_size' parameter to 'all'.")
params['page_size'] = 'all'
params['page_size'] = max_results or 'all'
# Performs the request for the first page
response = self.get(
self.get_url_for('%s-list' % obj_name, **kwargs),
self.get_url_for(endpoint),
params=params
)
results = response['results']
......@@ -486,20 +488,20 @@ class Re2oAPIClient:
# Returns the exact number of results if applicable
ret = results[:max_results] if max_results else results
self.log.debug("Listing {} objects successful".format(obj_name))
self.log.debug("Listing objects under '{}' successful"
.format(endpoint))
return ret
def _count_for(self, obj_name, params={}, **kwargs):
"""Count all '{obj_name}' objects on the server:
def count(self, endpoint, params={}):
"""Count all objects on the server that corresponds to the given
endpoint. The endpoint must be valid for listing objects.
Args:
endpoint: The path of the endpoint.
params: See `requests.get` params.
**kwargs: A dictionnary used to defines the required parameters
in order to build the URL (using `.format()`).
Returns:
The number of {obj_name} objects on the server as returned by the
API.
The number of objects on the server as returned by the API.
Raises:
requests.exceptions.RequestException: An error occured while
......@@ -507,9 +509,10 @@ class Re2oAPIClient:
exceptions.PermissionDenied: The user does not have the right
to perform this request.
"""
self.log.info("Starting counting {} objects".format(obj_name))
self.log.info("Starting counting objects under '{}'"
.format(endpoint))
# For optimization, ask fo only 1 result (so the server will take
# For optimization, ask for only 1 result (so the server will take
# less time to process the request) unless the user is forcing the
# use of a different `page_size`.
if not 'page_size' in params.keys():
......@@ -518,24 +521,24 @@ class Re2oAPIClient:
# Performs the request and return the `count` value in the response.
ret = self.get(
self.get_url_for('%s-list' % obj_name, **kwargs),
self.get_url_for(endpoint),
params=params
)['count']
self.log.debug("Counting {} objects successful".format(obj_name))
self.log.debug("Counting objects under '{}' successful"
.format(endpoint))
return ret
def _view_for(self, obj_name, params={}, **kwargs):
"""Retrieved the details of a '{obj_name}' object from the server.
def view(self, endpoint, params={}):
"""Retrieved the details of an object from the server that corresponds
to the given endpoint.
Args:
endpoint: The path of the endpoint.
params: See `requests.get` params.
**kwargs: A dictionnary used to defines the required parameters
in order to build the URL (using `.format()`).
Returns:
The serialized data of the queried {obj_name} object as returned
by the API.
The serialized data of the queried object as returned by the API.
Raises:
requests.exceptions.RequestException: An error occured while
......@@ -543,53 +546,13 @@ class Re2oAPIClient:
exceptions.PermissionDenied: The user does not have the right
to perform this request.
"""
self.log.info("Starting viewing a {} object".format(obj_name))
self.log.info("Starting viewing an object under '{}'"
.format(endpoint))
ret = self.get(
self.get_url_for('%s-detail' % obj_name, **kwargs),
self.get_url_for(endpoint),
params=params
)
self.log.debug("Viewing {} object successful".format(obj_name))
self.log.debug("Viewing object under '{}' successful"
.format(endpoint))
return ret
def __getattr__(self, item):
if item.startswith('list_'):
obj_name = item[len('list_'):]
def f(*args, **kwargs):
return self._list_for(obj_name, *args, **kwargs)
f.__doc__ = self._list_for.__doc__.format(obj_name=obj_name)
f.__name__ = "list_"+obj_name
return f
elif item.startswith('count_'):
obj_name = item[len('count_'):]
def f(*args, **kwargs):
return self._count_for(obj_name, *args, **kwargs)
f.__doc__ = self._count_for.__doc__.format(obj_name=obj_name)
f.__name__ = "count_"+obj_name
return f
elif item.startswith('view_'):
obj_name = item[len('view_'):]
def f(*args, **kwargs):
return self._view_for(obj_name, *args, **kwargs)
f.__doc__ = self._view_for.__doc__.format(obj_name=obj_name)
f.__name__ = "view_"+obj_name
return f
else:
raise AttributeError(item)
def __dir__(self):
ret = ['use_tls', 'token_file', 'hostname', 'token',
'need_renew_token', 'get_token', 'delete', 'get', 'patch',
'post', 'put', 'get_url_for']
for name in endpoints.get_names():
if name.endswith('-list'):
ret.append('list_%s' % name[:-len('-list')])
ret.append('count_%s' % name[:-len('-list')])
elif name.endswith('-detail'):
ret.append('view_%s' % name[:-len('-detail')])
return ret
from . import exceptions
urls = {
'root': '/api/',
'article-list': '/api/cotisations/article/',
'article-detail': '/api/cotisations/article/{pk}/',
'banque-list': '/api/cotisations/banque/',
'banque-detail': '/api/cotisations/banque/{pk}/',
'cotisation-list': '/api/cotisations/cotisation/',
'cotisation-detail': '/api/cotisations/cotisation/{pk}/',
'facture-list': '/api/cotisations/facture/',
'facture-detail': '/api/cotisations/facture/{pk}/',
'paiment-list': '/api/cotisations/paiement/',
'paiement-detail': '/api/cotisations/paiement/{pk}/',
'vente-list': '/api/cotisations/vente/',
'vente-detail': '/api/cotisations/vente/{pk}/',
'domain-list': '/api/machines/domain/',
'domain-detail': '/api/machines/domain/{pk}/',
'extension-list': '/api/machines/extension/',
'extension-detail': '/api/machines/extension/{pk}/',
'interface-list': '/api/machines/interface/',
'interface-detail': '/api/machines/interface/{pk}/',
'iplist-list': '/api/machines/iplist/',
'iplist-detail': '/api/machines/iplist/{pk}/',
'iptype-list': '/api/machines/iptype/',
'iptype-detail': '/api/machines/iptype/{pk}/',
'ipv6list-list': '/api/machines/ipv6list/',
'ipv6list-detail': '/api/machines/ipv6list/{pk}/',
'machine-list': '/api/machines/machine/',
'machine-detail': '/api/machines/machine/{pk}/',
'machinetype-list': '/api/machines/machinetype/',
'machinetype-detail': '/api/machines/machinetype/{pk}/',
'mx-list': '/api/machines/mx/',
'mx-detail': '/api/machines/mx/{pk}/',
'nas-list': '/api/machines/nas/',
'nas-detail': '/api/machines/nas/{pk}/',
'ns-list': '/api/machines/ns/',
'ns-detail': '/api/machines/ns/{pk}/',
'ouvertureportlist-list': '/api/machines/ouvertureportlist/',
'ouvertureportlist-detail': '/api/machines/ouvertureportlist/{pk}/',
'ouvertureport-list': '/api/machines/ouvertureport/',
'ouvertureport-detail': '/api/machines/ouvertureport/{pk}/',
'servicelink-list': '/api/machines/servicelink/',
'servicelink-detail': '/api/machines/servicelink/{pk}/',
'service-list': '/api/machines/service/',
'service-detail': '/api/machines/service/{pk}/',
'soa-list': '/api/machines/soa/',
'soa-detail': '/api/machines/soa/{pk}/',
'srv-list': '/api/machines/srv/',
'srv-detail': '/api/machines/srv/{pk}/',
'txt-list': '/api/machines/txt/',
'txt-detail': '/api/machines/txt/{pk}/',
'vlan-list': '/api/machines/vlan/',
'vlan-detail': '/api/machines/vlan/{pk}/',
'optionaluser-detail': '/api/preferences/optionaluser/',
'optionalmachine-detail': '/api/preferences/optionalmachine/',
'optionaltopologie-detail': '/api/preferences/optionaltopologie/',
'generaloption-detail': '/api/preferences/generaloption/',
'homeservice-list': '/api/preferences/service/',
'homeservice-detail': '/api/preferences/service/{pk}/',
'assooption-detail': '/api/preferences/assooption/',
'homeoption-detail': '/api/preferences/homeoption/',
'mailmessageoption-detail': '/api/preferences/mailmessageoption/',
'accesspoint-list': '/api/topologie/acesspoint/',
'accesspoint-detail': '/api/topologie/acesspoint/{pk}/',
'building-list': '/api/topologie/building/',
'building-detail': '/api/topologie/building/{pk}/',
'constructorswitch-list': '/api/topologie/constructorswitch/',
'constructorswitch-detail': '/api/topologie/constructorswitch/{pk}/',
'modelswitch-list': '/api/topologie/modelswitch/',
'modelswitch-detail': '/api/topologie/modelswitch/{pk}/',
'room-list': '/api/topologie/room/',
'room-detail': '/api/topologie/room/{pk}/',
'server-list': '/api/topologie/server/',
'server-detail': '/api/topologie/server/{pk}/',
'stack-list': '/api/topologie/stack/',
'stack-detail': '/api/topologie/stack/{pk}/',
'switch-list': '/api/topologie/switch/',
'switch-detail': '/api/topologie/switch/{pk}/',
'switchbay-list': '/api/topologie/switchbay/',
'switchbay-detail': '/api/topologie/switchbay/{pk}/',
'switchport-list': '/api/topologie/switchport/',
'switchport-detail': '/api/topologie/switchport/{pk}/',
'adherent-list': '/api/users/adherent/',
'adherent-detail': '/api/users/adherent/{pk}/',
'ban-list': '/api/users/ban/',
'ban-detail': '/api/users/ban/{pk}/',
'club-list': '/api/users/club/',
'club-detail': '/api/users/club/{pk}/',
'listright-list': '/api/users/listright/',
'listright-detail': '/api/users/listright/{pk}/',
'school-list': '/api/users/school/',
'school-detail': '/api/users/school/{pk}/',
'serviceuser-list': '/api/users/serviceuser/',
'serviceuser-detail': '/api/users/serviceuser/{pk}/',
'shell-list': '/api/users/shell/',
'shell-detail': '/api/users/shell/{pk}/',
'user-list': '/api/users/user/',
'user-detail': '/api/users/user/{pk}/',
'whitelist-list': '/api/users/whitelist/',
'whitelist-detail': '/api/users/whitelist/{pk}/',
'dnszones-list': '/api/dns/zones/',
'hostmacip-list': '/api/dhcp/hostmacip/',
'mailingstandard-list': '/api/mailing/standard/',
'mailingclub-list': '/api/mailing/club/',
'servicesregen-list': '/api/services/regen/',
'servicesregen-detail': '/api/services/regen/{pk}/',
'token': '/api/token-auth/',
}
def get_names():
return urls.keys()
def get_endpoint_for(name, logger=None, **kwargs):
try:
url=urls[name]
except KeyError:
e = exceptions.URLNameDoesNotExists(name)
if logger is not None:
logger.warning(e)
raise e
else:
try:
return url.format_map(kwargs)
except KeyError as e:
e = exceptions.URLParameterMissing(name, e)
if logger is not None:
logger.warning(e)
raise e
......@@ -7,14 +7,6 @@ class APIClientGenericError(ValueError):
super(APIClientGenericError, self).__init__(self.message)
class URLNameDoesNotExists(APIClientGenericError):
template = "The name '{}' was not foud among the possible endpoints."
class URLParameterMissing(APIClientGenericError):
template = "The url named '{}' requires the parameter {} to be built."
class InvalidCredentials(APIClientGenericError):
template = "The credentials for {}@{} are not valid."
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment