Пример #1
0
class TestClass(object):
    __metaclass__ = RestClientMetaClass
    some_resource = RestResource(
        "some_resource",
        "/{resource_one_id}/subresources/{resource_two_id}")
    extra_views_resource = RestResource(
        "books",
        "/{resource_one_id}/books/{bookid}",
        extra_views=["unavailable",
                     {"name": "get_all_books_status", "path": "status"}])
    detail_only_resource = RestResource(
        "auction",
        "/users/{user_id}/auctions/{auction_id}",
        methods=["detail"])
    extra_object_view_resource = RestResource(
        "tools",
        "/sheds/{shed_id}/tools/{tool_id}",
        extra_views=[
            {"name": "get_tool_users", "path": "users", "scope": "object"}]
    )
    custom_names_resource = RestResource(
        "stupidname",
        "/place/{objid}",
        method_names={
            "list": "get_birds",
            "object": "get_bird",
            "create": "create_bird",
            "update": "update_bird",
            "delete": "delete_bird"
        })
Пример #2
0
class ExtraViewsResourceTestCase(unittest.TestCase):

    def setUp(self):
        self.resource = RestResource(
            "somresource",
            "/{id1}/somesubresource/{id2}",
            extra_views=[
                {"path": "status", "name":  "all_devices_status"},
                "missing",
                {"path": "children", "name": "subresource_children",
                 "scope": "object"},
                {"path": "ingredients", "name": "ingredients",
                 "scope": "object", "method": "put"}]
        )

    def test_extra_view_returns_correct_url(self):
        request = self.resource.get_extra_view_request("status", id1=1)
        self.assertEqual(request.path, "/1/somesubresource/status")

    def test_extra_view_with_object_scope_returns_correct_url(self):
        request = self.resource.get_extra_view_request("children", id1=1,
                                                       id2=2)
        self.assertEqual(request.path, "/1/somesubresource/2/children")

    def test_extra_views_described_by_dictionary(self):
        for view_desc in self.resource.extra_views:
            if view_desc["name"] == "all_devices_status":
                self.assertEqual(view_desc["path"], "status")

    def test_extra_views_described_by_string(self):
        for view_desc in self.resource.extra_views:
            if view_desc["name"] == "missing":
                self.assertEqual(view_desc["path"], "missing")
                self.assertEqual(view_desc["name"], "get_missing")

    def test_scope_added_if_not_specified(self):
        for view_desc in self.resource.extra_views:
            if view_desc["path"] == "status":
                self.assertEqual(view_desc["scope"], "aggregate")

    def test_specified_scope_takes_precedence(self):
        for view_desc in self.resource.extra_views:
            if view_desc["path"] == "children":
                self.assertEqual(view_desc["scope"], "object")

    def test_default_method_is_get(self):
        request = self.resource.get_extra_view_request("children", id1=1,
                                                       id2=2)
        self.assertEqual(request.method, "get")

    def test_specified_method_used(self):
        request = self.resource.get_extra_view_request("ingredients", id1=1,
                                                       id2=2)
        self.assertEqual(request.method, "put")
Пример #3
0
 def setUp(self):
     self.resource = RestResource(
         "somresource",
         "/{id1}/somesubresource/{id2}",
         extra_views=[
             {"path": "status", "name":  "all_devices_status"},
             "missing",
             {"path": "children", "name": "subresource_children",
              "scope": "object"},
             {"path": "ingredients", "name": "ingredients",
              "scope": "object", "method": "put"}]
     )
Пример #4
0
class RestResourceTestCase(unittest.TestCase):

    def setUp(self):
        self.path = "/{argument1}/subresource/{argument2}"
        self.resource = RestResource(
            "subresource", "/{argument1}/subresource/{argument2}")

    def test_resource_generates_required_args_for_all_but_last(self):
        self.assertEqual(self.resource.required_args, ["argument1"])

    def test_resource_generates_correct_object_arg(self):
        self.assertEqual(self.resource.object_arg, 'argument2')

    def test_resource_with_no_args_generates_error(self):
        with self.assertRaises(ValueError):
            resource = RestResource("somename", "/blahblah/blah")

    def test_resource_with_no_required_args_correct(self):
        resource = RestResource("somename", "/sompath/{someobj_id}")
        self.assertEqual(resource.required_args, [])
        self.assertEqual(resource.object_arg, "someobj_id")

    def test_resource_path_correctly_calculated(self):
        self.assertEqual(self.resource.path, "/{argument1}/subresource")

    def test_resource_list_method_hits_correct_url(self):
        request = self.resource.get_list_request(argument1=1)
        self.assertEqual(request.path, "/1/subresource")

    def test_resource_individual_method_hits_correct_url(self):
        request = self.resource.get_object_request(argument1=1, argument2=2)
        self.assertEqual(request.path, "/1/subresource/2")

    def test_update_resource_correct_url_and_method(self):
        request = self.resource.get_update_object_request(argument1=1,
                                                          argument2=2)
        self.assertEqual(request.path, "/1/subresource/2")
        self.assertEqual(request.method, 'post')

    def test_delete_resource_correct_url_and_method(self):
        request = self.resource.get_delete_object_request(argument1=1,
                                                          argument2=2)
        self.assertEqual(request.path, "/1/subresource/2")
        self.assertEqual(request.method, 'delete')

    def test_create_resource_correct_url_and_method(self):
        request = self.resource.get_create_object_request(argument1=1)
        self.assertEqual(request.path, "/1/subresource")
        self.assertEqual(request.method, 'put')
Пример #5
0
 def test_resource_path_calculated_correctly(self):
     # Catch a bug where the url /accounts/{account_id}/phone_numbers/{phone_number}
     # was parsing incorrectly
     resource = RestResource("phone_numbers",
                             "/accounts/{account_id}/phone_numbers/{phone_number}")
     self.assertEqual(resource.path,
                      "/accounts/{account_id}/phone_numbers")
Пример #6
0
 def test_custom_resource_names(self):
     method_names={"list":"get_books",
                   "object": "get_book",
                   "update": "update_book",
                   "create": "create_book",
                   "delete": "delete_book"}
     resource = RestResource("someresource", "/someplace/{resource_id}",
                             method_names=method_names)
     self.assertEqual(resource.method_names, method_names)
Пример #7
0
 def test_resource_names_for_default_method_names(self):
     resource = RestResource("someresource", "/someplace/{resource_id}")
     method_names = resource.method_names
     expected_names = {"list": "get_someresources",
                       "object": "get_someresource",
                       "update": "update_someresource",
                       "create": "create_someresource",
                       "delete": "delete_someresource"}
     self.assertEqual(expected_names, method_names)
Пример #8
0
 def test_custom_resource_names_merged_with_default(self):
     method_names = {"list": "get_books", "create": "create_book"}
     resource = RestResource("someresource", "/someplace/{resource_id}",
                             method_names=method_names)
     expected_names = dict(method_names)
     expected_names.update({
         "object": "get_someresource",
         "update": "update_someresource",
         "delete": "delete_someresource"
     })
     self.assertEqual(expected_names, resource.method_names)
Пример #9
0
class Client(object):
    """The interface to the Kazoo API

    This class should be initialized either with a username, password and
    account name combination, or with an API key. Once you have initialized
    the client you will need to call :meth:`authenticate()` before you can
    begin making API calls. ::

        >>>import kazoo
        >>>client = kazoo.Client(api_key="sdfasdfas")
        >>>client.authenticate()

    You can also initialize with a username and password combination: ::

        >>>client = kazoo.Client(username="******", password="******", account_name="my_account_name")
        >>>client.authenticate()

    API calls which require data take it in the form of a required argument
    called 'data' which is the last argument to the method. For example ::

        >>>client.update_account(acct_id, {"name": "somename", "realm":"superfunrealm"})

    Dictionaries and lists will automatically be converted to their appropriate
    representation so you can do things like: ::

        >>>client.update_callflow(acct_id, callflow_id, {"flow":{"module":"somemodule"}})

    Invalid data will result in an exception explaining the problem.

    The server response is returned from each method as a python dictionary of
    the returned JSON object, for example: ::

        >>>client.get_account(acct_id)
        {u'auth_token': u'abc437d000007d0454cc984f6f09daf3',
         u'data': {u'billing_mode': u'normal',
          u'caller_id': {},
          u'caller_id_options': {},
          u'id': u'c4f64412ad0057222c0009a3e7da011',
          u'media': {u'bypass_media': u'auto'},
          u'music_on_hold': {},
          u'name': u'test3',
          u'notifications': {},
          u'realm': u'4c8050.sip.2600hz.com',
          u'superduper_admin': False,
          u'timezone': u'America/Los_Angeles',
          u'wnm_allow_additions': False},
         u'request_id': u'ea6441422fb85000ad21db4f1e2326c1',
         u'revision': u'3-c16dd0a629fe1da0000e1e7b3e5fb35a',
         u'status': u'success'}

    For each resource exposed by the kazoo api there are corresponding methods
    on the client. For example, for the 'callflows' resource the
    correspondence is as follows. ::

        GET /accounts/{account_id}/callflows -> client.get_callflows(acct_id)
        GET /accounts/{account_id}/callflows/{callflow_id} -> client.get_callflow(acct_id, callflow_id)
        PUT /accounts/{account_id}/callflows/ -> client.create_callflow(acct_id, data)
        POST /account/{account_id}/callflows/{callflow_id} -> client.update_callflow(acct_id, data)
        DELETE /account/{account_id}/callflows/{callflow_id} -> client.delete_callflow(acct_id, callflow_id)

    Some resources do not have all methods available, in which case they are
    not present on the client.

    There are also some resources which don't quite fit this paradigm, they are: ::

        GET /accounts/{account_id}/media -> client.get_all_media(acct_id)
        GET /accounts/{account_id}/children -> client.get_account_children(acct_id)
        GET /accounts/{account_id}/descendants -> client.get_account_descendants(acct_id)
        GET /accounts/{account_id}/devices/status -> client.get_all_devices_status(acct_id)
        GET /accounts/{account_id}/servers/{server_id}/deployment -> client.get_deployment(acct_id, server_id)
        GET /accounts/{account_id}/users/hotdesk -> client.get_hotdesk(acct_id)

    """
    __metaclass__ = RestClientMetaClass
    BASE_URL = "http://api.2600hz.com:8000/v1"

    _accounts_resource = RestResource(
        "account",
        "/accounts/{account_id}",
        exclude_methods=["list", "delete", "create"],
        extra_views=[{
            "name": "get_account_children",
            "path": "children",
            "scope": "object"
        }, {
            "name": "get_account_descendants",
            "path": "descendants",
            "scope": "object"
        }])
    _callflow_resource = RestResource(
        "callflow", "/accounts/{account_id}/callflows/{callflow_id}")
    _conference_resource = RestResource(
        "conference", "/accounts/{account_id}/conferences/{conference_id}")
    _device_resource = RestResource(
        "device",
        "/accounts/{account_id}/devices/{device_id}",
        extra_views=[{
            "name": "get_all_devices_status",
            "path": "status"
        }])
    _directories_resource = RestResource(
        "directory",
        "/accounts/{account_id}/directories/{directory_id}",
        plural_name="directories")
    _global_resources = RestResource(
        "global_resource",
        "/accounts/{account_id}/global_resources/{resource_id}")
    _limits_resource = RestResource("limit",
                                    "/accounts/{account_id}/limits/{ignored}",
                                    methods=["list"])
    _local_resources_resource = RestResource(
        "local_resource",
        "/accounts/{account_id}/local_resources/{resource_id}")
    _media_resource = RestResource("media",
                                   "/accounts/{account_id}/media/{media_id}",
                                   plural_name="media",
                                   method_names={"list": "get_all_media"})
    _menus_resource = RestResource("menu",
                                   "/accounts/{account_id}/menus/{menu_id}")
    _phone_number_resource = RestResource(
        "phone_number",
        "/accounts/{account_id}/phone_numbers/{phone_number}",
        methods=["list", "update", "delete"],
        extra_views=[{
            "name": "activate_phone_number",
            "path": "activate",
            "scope": "object",
            "method": "put"
        }, {
            "name": "reserve_phone_number",
            "path": "reserve",
            "scope": "object",
            "method": "put"
        }, {
            "name": "add_port_in_number",
            "path": "port",
            "scope": "object",
            "method": "put"
        }])
    _queues_resource = RestResource(
        "queue", "/accounts/{account_id}/queues/{queue_id}")
    _server_resource = RestResource(
        "server",
        "/accounts/{account_id}/servers/{server_id}",
        methods=["list"],
        extra_views=[{
            "name": "get_deployment",
            "path": "deployment",
            "scope": "object"
        }, {
            "name": "create_deployment",
            "path": "deployment",
            "scope": "object",
            "method": "put"
        }, {
            "name": "get_server_log",
            "path": "log"
        }])
    _temporal_rules_resource = RestResource(
        "temporal_rule", "/accounts/{account_id}/temporal_rules/{rule_id}")
    _users_resource = RestResource("user",
                                   "/accounts/{account_id}/users/{user_id}",
                                   extra_views=[{
                                       "name": "get_hotdesk",
                                       "path": "hotdesks"
                                   }])
    _vmbox_resource = RestResource("voicemail_box",
                                   "/accounts/{account_id}/vmboxes/{vmbox_id}",
                                   plural_name="voicemail_boxes")
    _phone_number_docs_resource = RestResource(
        "phone_number_doc",
        "/accounts/{account_id}/phone_numbers/{phone_number}/docs/{filename}",
        methods=["delete"],
    )

    def __init__(self,
                 api_key=None,
                 password=None,
                 account_name=None,
                 username=None):
        if not api_key and not password:
            raise RuntimeError("You must pass either an api_key or an "
                               "account name/password pair")

        if password or account_name or username:
            if not (password and account_name and username):
                raise RuntimeError("If using account name/password "
                                   "authentication then you must specify "
                                   "password, userame and account_name "
                                   "arguments")
            self.auth_request = UsernamePasswordAuthRequest(
                username, password, account_name)
        else:
            self.auth_request = ApiKeyAuthRequest(api_key)

        self.api_key = api_key
        self._authenticated = False
        self.auth_token = None

    def authenticate(self):
        """Call this before making other api calls to fetch an auth token
        which will be automatically used for all further requests
        """
        if not self._authenticated:
            self.auth_data = self.auth_request.execute(self.BASE_URL)
            self.auth_token = self.auth_data["auth_token"]
            self._authenticated = True
        return self.auth_token

    def _execute_request(self, request, **kwargs):
        if request.auth_required:
            kwargs["token"] = self.auth_token
        return request.execute(self.BASE_URL, **kwargs)

    def search_phone_numbers(self, prefix, quantity=10):
        request = KazooRequest("/phone_numbers",
                               get_params={
                                   "prefix": prefix,
                                   "quantity": quantity
                               })
        return self._execute_request(request)

    def create_phone_number(self, acct_id, phone_number):
        request = KazooRequest(
            "/accounts/{account_id}/phone_numbers/{phone_number}",
            method="put")
        return self._execute_request(request,
                                     account_id=acct_id,
                                     phone_number=phone_number)

    def upload_phone_number_file(self, acct_id, phone_number, filename,
                                 file_obj):
        """Uploads a file like object as part of a phone numbers documents"""
        request = KazooRequest(
            "/accounts/{account_id}/phone_numbers/{phone_number}",
            method="post")
        return self._execute_request(request, files={filename: file_obj})
Пример #10
0
 def setUp(self):
     self.path = "/{argument1}/subresource/{argument2}"
     self.resource = RestResource(
         "subresource", "/{argument1}/subresource/{argument2}")
Пример #11
0
 def test_resource_with_no_required_args_correct(self):
     resource = RestResource("somename", "/sompath/{someobj_id}")
     self.assertEqual(resource.required_args, [])
     self.assertEqual(resource.object_arg, "someobj_id")
Пример #12
0
 def test_resource_with_no_args_generates_error(self):
     with self.assertRaises(ValueError):
         resource = RestResource("somename", "/blahblah/blah")
Пример #13
0
 def test_excludes_resource(self):
     resource = RestResource("subresource", "/{oneid}/someplace",
                             exclude_methods=["list", "detail"])
     self.assertEqual(resource.methods, ["create", "update", "delete"])
Пример #14
0
 def test_if_plural_name_set_in_constructor_then_use_that(self):
     resource = RestResource("subresource", "/{oneid}/someotherplace",
                             plural_name="subresourcae")
     self.assertEqual(resource.plural_name, "subresourcae")
Пример #15
0
 def test_resource_plural_name(self):
     resource = RestResource("subresource", "/{oneid}/someotherplace")
     self.assertEqual(resource.plural_name, "subresources")