diff --git a/pillarsdk/api.py b/pillarsdk/api.py index 405b3e6..6f655cb 100644 --- a/pillarsdk/api.py +++ b/pillarsdk/api.py @@ -199,3 +199,25 @@ class Api(object): """ return self.request(utils.join_url(self.endpoint, action), 'DELETE', headers=headers) + + def OPTIONS(self, action, headers=None): + """Make OPTIONS request. + + Contrary to other requests, this method returns the raw requests.Response object. + + :rtype: requests.Response + """ + + http_headers = utils.merge_dict(self.headers(), headers) + url = utils.join_url(self.endpoint, action) + response = self.requests_session.request('OPTIONS', url, headers=http_headers) + + if 200 <= response.status_code <= 299: + return response + + exception = exceptions.exception_for_status(response.status_code) + if exception: + raise exception(response, response.text) + + raise exceptions.ConnectionError(response, response.text, + "Unknown response code: %s" % response.status_code) diff --git a/pillarsdk/projects.py b/pillarsdk/projects.py index 918fb60..aa15284 100644 --- a/pillarsdk/projects.py +++ b/pillarsdk/projects.py @@ -5,7 +5,7 @@ from .resource import Post from .resource import Update from .resource import Delete from .resource import Replace -from .exceptions import ResourceNotFound +from .exceptions import ResourceNotFound, ForbiddenAccess from . import utils from .nodes import Node @@ -87,18 +87,20 @@ class Project(List, Find, Create, Post, Update, Delete, Replace): method. """ api = api or Api.Default() - url = utils.join_url(self.path, str(self._id)) - params = {'projection': '{"permissions":1, "name": 1, "node_types": 1, \ - "url": 1, "user": 1}', - 'node_type': node_type_name} - url = utils.join_url_params(url, params) - response = api.get(url) - node_type = next((item for item in response['node_types'] if - item['name'] and item['name'] == node_type_name), - None) - if node_type is None or 'allowed_methods' not in node_type: + url = utils.join_url('/p', str(self._id), node_type_name) + + # Perform the HTTP OPTIONS request. + options = api.OPTIONS(url) + + # Obtain the Accept header, warning if it doesn't exist. + try: + accept_hdr = options.headers['Allowed'] + except KeyError: + self.log.warning('OPTIONS call to %r did not return an Accept header.', url) return False - return method in node_type['allowed_methods'] + + methods = {meth.strip() for meth in accept_hdr.split(',')} + return method in methods def _manage_user(self, user_id, action, api=None): """Add or remove a user to a project give its ObjectId.""" diff --git a/pillarsdk/resource.py b/pillarsdk/resource.py index 09128b0..d1e1880 100644 --- a/pillarsdk/resource.py +++ b/pillarsdk/resource.py @@ -1,3 +1,4 @@ +import logging import uuid from . import utils @@ -15,6 +16,9 @@ class Resource(object): attributes = attributes or {} self.__dict__['api'] = Api.Default() + logger = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) + super(Resource, self).__setattr__('log', logger) + super(Resource, self).__setattr__('__data__', {}) super(Resource, self).__setattr__('error', None) super(Resource, self).__setattr__('headers', {})