From 099c06d672d17dde8cd716aadd67c374c4be9851 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Fri, 26 Jun 2015 15:08:05 -0700 Subject: [PATCH 01/13] porting to python --- .../test_task_router_capability.py | 253 ++++++++++++++++++ .../test_task_router_taskqueue_capability.py | 132 +++++++++ .../test_task_router_worker_capability.py | 162 +++++++++++ .../test_task_router_workspace_capability.py | 131 +++++++++ twilio/task_router/__init__.py | 144 ---------- twilio/task_router/capability/__init__.py | 10 + .../task_router/capability/capability_api.py | 68 +++++ .../capability/task_router_capability.py | 184 +++++++++++++ 8 files changed, 940 insertions(+), 144 deletions(-) create mode 100644 tests/task_router/test_task_router_capability.py create mode 100644 tests/task_router/test_task_router_taskqueue_capability.py create mode 100644 tests/task_router/test_task_router_worker_capability.py create mode 100644 tests/task_router/test_task_router_workspace_capability.py delete mode 100644 twilio/task_router/__init__.py create mode 100644 twilio/task_router/capability/__init__.py create mode 100644 twilio/task_router/capability/capability_api.py create mode 100644 twilio/task_router/capability/task_router_capability.py diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py new file mode 100644 index 0000000000..35b1cb7678 --- /dev/null +++ b/tests/task_router/test_task_router_capability.py @@ -0,0 +1,253 @@ +import sys + +import time +import unittest +import warnings + +from twilio import jwt +from twilio.task_router.capability import TaskRouterCapability + +class TaskRouterCapabilityTest(unittest.TestCase): + + def test_workspace_default(self): + account_sid = "AC123" + auth_token = "foobar" + workspace_sid = "WS456" + channel_id = "WS456" + capability = TaskRouterCapability(account_sid, auth_token, workspace_sid, channel_id) + + capability.generate_token() + + token = capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["channel"], channel_id) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], channel_id) + + policies = decoded['policies'] + self.assertEqual(len(policies), 3) + + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + def test_worker_default(self): + account_sid = "AC123" + auth_token = "foobar" + workspace_sid = "WS456" + worker_sid = "WK789" + capability = TaskRouterCapability(account_sid, auth_token, workspace_sid, worker_sid) + + capability.generate_token() + + token = capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["worker_sid"], worker_sid) + self.assertEqual(decoded["channel"], worker_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], worker_sid) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # activity GET + fetch_activity = policies[0] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) + self.assertEqual("GET", fetch_activity['method']) + self.assertTrue(fetch_activity['allowed']) + self.assertEqual({}, fetch_activity['query_filter']) + self.assertEqual({}, fetch_activity['post_filter']) + + # websocket GET + get_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[2] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[3] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + def test_task_queue_default(self): + account_sid = "AC123" + auth_token = "foobar" + workspace_sid = "WS456" + taskqueue_sid = "WQ789" + capability = TaskRouterCapability(account_sid, auth_token, workspace_sid, taskqueue_sid) + + capability.generate_token() + + token = capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["taskqueue_sid"], taskqueue_sid) + self.assertEqual(decoded["channel"], taskqueue_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], taskqueue_sid) + + policies = decoded['policies'] + self.assertEqual(len(policies), 3) + + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + def test_deprecated_worker(self): + account_sid = "AC123" + auth_token = "foobar" + workspace_sid = "WS456" + worker_sid = "WK789" + capability = TaskRouterCapability(account_sid, auth_token, workspace_sid, worker_sid) + + capability.generate_token() + + token = capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["worker_sid"], worker_sid) + self.assertEqual(decoded["channel"], worker_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], worker_sid) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # should expect 4 policies + + # activity GET + fetch_activity = policies[0] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) + self.assertEqual("GET", fetch_activity['method']) + self.assertTrue(fetch_activity['allowed']) + self.assertEqual({}, fetch_activity['query_filter']) + self.assertEqual({}, fetch_activity['post_filter']) + + # websocket GET + get_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[2] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[3] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + # check deprecated warnings + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + capability.allow_worker_fetch_attributes() + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + assert "deprecated" in str(w[-1].message) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + capability.allow_worker_activity_updates() + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + assert "deprecated" in str(w[-1].message) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + capability.allow_task_reservation_updates() + assert len(w) == 1 + assert issubclass(w[-1].category, DeprecationWarning) + assert "deprecated" in str(w[-1].message) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/tests/task_router/test_task_router_taskqueue_capability.py b/tests/task_router/test_task_router_taskqueue_capability.py new file mode 100644 index 0000000000..bd3cec6295 --- /dev/null +++ b/tests/task_router/test_task_router_taskqueue_capability.py @@ -0,0 +1,132 @@ +import sys +import time +import unittest + +from twilio import jwt +from twilio.task_router.capability import TaskRouterTaskQueueCapability + +class TaskRouterTaskQueueCapabilityTest(unittest.TestCase): + + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.taskqueue_sid = "WQ789" + self.capability = TaskRouterTaskQueueCapability(self.account_sid, self.auth_token, self.workspace_sid, self.taskqueue_sid) + + def test_generate_token(self): + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["taskqueue_sid"], self.taskqueue_sid) + self.assertEqual(decoded["channel"], self.taskqueue_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.taskqueue_sid) + + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + + def test_generate_token_with_custom_ttl(self): + ttl = 10000 + + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + + def test_default(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 3) + + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + def test_allow_fetch_subresources(self): + self.capability.allow_fetch_subresources() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # confirm the additional policy generated with allow_fetch_subresources() + + policy = policies[3] + + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") + self.assertEqual(policy['method'], "GET") + self.assertTrue(policy['allowed']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + + def test_allow_updates_subresources(self): + self.capability.allow_updates_subresources() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # confirm the additional policy generated with allow_updates_subresources() + + policy = policies[3] + + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") + self.assertEqual(policy['method'], "POST") + self.assertTrue(policy['allowed']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py new file mode 100644 index 0000000000..030190747d --- /dev/null +++ b/tests/task_router/test_task_router_worker_capability.py @@ -0,0 +1,162 @@ +import sys + +import time +import unittest +import warnings + +from twilio import jwt +from twilio.task_router.capability import TaskRouterWorkerCapability + +class TaskRouterWorkerCapabilityTest(unittest.TestCase): + + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.worker_sid = "WK789" + self.capability = TaskRouterWorkerCapability(self.account_sid, self.auth_token, self.workspace_sid, self.worker_sid) + + def test_generate_token(self): + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["worker_sid"], self.worker_sid) + self.assertEqual(decoded["channel"], self.worker_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.worker_sid) + + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + + def test_generate_token_with_custom_ttl(self): + ttl = 10000 + + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + + def test_defaults(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + websocket_url = 'https://event-bridge.twilio.com/v1/wschannels/%s/%s' % (self.account_sid, self.worker_sid) + + # expect 5 policies + policies = decoded['policies'] + self.assertEqual(len(policies), 5) + + # policy 0 - GET websocket + get_policy = policies[0] + self.assertIsNotNone(get_policy) + self.assertEqual(get_policy['url'], websocket_url) + self.assertEqual(get_policy['method'], 'GET') + self.assertTrue(get_policy['allowed']) + self.assertEqual(get_policy['query_filter'], {}) + self.assertEqual(get_policy['post_filter'], {}) + + # policy 1 - POST + post_policy = policies[1] + self.assertIsNotNone(post_policy) + self.assertEqual(post_policy['url'], websocket_url) + self.assertEqual(post_policy['method'], 'POST') + self.assertTrue(post_policy['allowed']) + self.assertEqual(post_policy['query_filter'], {}) + self.assertEqual(post_policy['post_filter'], {}) + + # policy 2 - Worker fetch + worker_fetch_policy = policies[2] + self.assertIsNotNone(worker_fetch_policy) + self.assertEqual(worker_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789') + self.assertEqual(worker_fetch_policy['method'], 'GET') + self.assertTrue(worker_fetch_policy['allowed']) + self.assertEqual(worker_fetch_policy['query_filter'], {}) + self.assertEqual(worker_fetch_policy['post_filter'], {}) + + # policy 3 - Reservation fetch + reservation_fetch_policy = policies[3] + self.assertIsNotNone(reservation_fetch_policy) + self.assertEqual(reservation_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**') + self.assertEqual(reservation_fetch_policy['method'], 'GET') + self.assertTrue(reservation_fetch_policy['allowed']) + self.assertEqual(reservation_fetch_policy['query_filter'], {}) + self.assertEqual(reservation_fetch_policy['post_filter'], {}) + + # policy 4 - Activity fetch + activity_fetch_policy = policies[4] + self.assertIsNotNone(activity_fetch_policy) + self.assertEqual(activity_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities') + self.assertEqual(activity_fetch_policy['method'], 'GET') + self.assertTrue(activity_fetch_policy['allowed']) + self.assertEqual(activity_fetch_policy['query_filter'], {}) + self.assertEqual(activity_fetch_policy['post_filter'], {}) + + def test_allow_activity_updates(self): + + # allow activity updates to the worker + self.capability.allow_activity_updates() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 6) + policy = policies[5] + + url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s" % (self.workspace_sid, self.worker_sid) + + self.assertEqual(url, policy["url"]) + self.assertEqual("POST", policy["method"]) + self.assertTrue(policy["allowed"]) + self.assertIsNotNone(policy['post_filter']) + self.assertEqual({}, policy['query_filter']) + self.assertTrue(policy['post_filter']['ActivitySid']) + + def test_allow_reservation_updates(self): + # allow reservation updates + self.capability.allow_reservation_updates() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 6) + + policy = policies[5] + + url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**" % self.workspace_sid + + self.assertEqual(url, policy["url"]) + self.assertEqual("POST", policy["method"]) + self.assertTrue(policy["allowed"]) + self.assertIsNotNone(policy["post_filter"]) + self.assertEqual({}, policy["query_filter"]) + self.assertTrue(policy["post_filter"]["ReservationStatus"]) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/task_router/test_task_router_workspace_capability.py b/tests/task_router/test_task_router_workspace_capability.py new file mode 100644 index 0000000000..cc389f7120 --- /dev/null +++ b/tests/task_router/test_task_router_workspace_capability.py @@ -0,0 +1,131 @@ +import sys + +import time +import unittest + +from twilio import jwt +from twilio.task_router.capability import TaskRouterWorkspaceCapability + +class TaskRouterWorkspaceCapabilityTest(unittest.TestCase): + + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.capability = TaskRouterWorkspaceCapability(self.account_sid, self.auth_token, self.workspace_sid) + + def test_generate_token(self): + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["channel"], self.workspace_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.workspace_sid) + + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + + def test_generate_token_with_custom_ttl(self): + ttl = 10000 + + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + + def test_default(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 3) + + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allowed']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) + + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allowed']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) + + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allowed']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) + + def test_allow_fetch_subresources(self): + self.capability.allow_fetch_subresources() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # confirm the additional policy generated with allow_fetch_subresources() + + policy = policies[3] + + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") + self.assertEqual(policy['method'], "GET") + self.assertTrue(policy['allowed']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + + def test_allow_updates_subresources(self): + self.capability.allow_updates_subresources() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 4) + + # confirm the additional policy generated with allow_updates_subresources() + + policy = policies[3] + + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") + self.assertEqual(policy['method'], "POST") + self.assertTrue(policy['allowed']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py deleted file mode 100644 index 17975c1cba..0000000000 --- a/twilio/task_router/__init__.py +++ /dev/null @@ -1,144 +0,0 @@ -import time - -from .. import jwt - - -TASK_ROUTER_BASE_URL = 'https://taskrouter.twilio.com' -TASK_ROUTER_BASE_WS_URL = 'https://event-bridge.twilio.com/v1/wschannels' - -REQUIRED = {'required': True} -OPTIONAL = {'required': False} - - -class TaskRouterCapability(object): - """ - A token to control permissions for the TaskRouter service. - - :param str account_sid: The account to generate a token for - :param str auth_token: The auth token for the account. Used to sign the - token and will not be included in generated output. - :param str workspace_sid: The workspace to grant capabilities over - :param str worker_sid: The worker sid to grant capabilities over - :param str base_url: The base TaskRouter API URL - :param str base_ws_url: The base TaskRouter event stream URL - """ - def __init__(self, account_sid, auth_token, workspace_sid, worker_sid, - base_url=TASK_ROUTER_BASE_URL, - version='v1', - base_ws_url=TASK_ROUTER_BASE_WS_URL): - self.account_sid = account_sid - self.auth_token = auth_token - self.workspace_sid = workspace_sid - self.worker_sid = worker_sid - self.version = version - self.base_url = '%s/%s' % (base_url, self.version) - self.base_ws_url = base_ws_url - self.policies = [] - - self._allow_worker_websocket_urls() - self._allow_activity_list_fetch() - - @property - def workspace_url(self): - return '%s/Workspaces/%s' % (self.base_url, self.workspace_sid) - - @property - def worker_url(self): - return '%s/Workers/%s' % (self.workspace_url, self.worker_sid) - - def _allow_worker_websocket_urls(self): - worker_event_url = '%s/%s/%s' % ( - self.base_ws_url, - self.account_sid, - self.worker_sid, - ) - self.policies.append(make_policy( - worker_event_url, - 'GET', - )) - self.policies.append(make_policy( - worker_event_url, - 'POST', - )) - - def _allow_activity_list_fetch(self): - self.policies.append(make_policy( - '%s/Activities' % self.workspace_url, - 'GET', - )) - - def allow_worker_activity_updates(self): - self.policies.append(make_policy( - self.worker_url, - 'POST', - post_filter={'ActivitySid': REQUIRED}, - )) - - def allow_worker_fetch_attributes(self): - self.policies.append(make_policy( - self.worker_url, - 'GET', - )) - - def allow_task_reservation_updates(self): - tasks_url = '%s/Tasks/**' % self.workspace_url - self.policies.append(make_policy( - tasks_url, - 'POST', - post_filter={'ReservationStatus': REQUIRED}, - )) - - def generate_token(self, ttl=3600, attributes=None): - """ - Generate a token string based on the credentials and permissions - previously configured on this object. - - :param int ttl: Expiration time in seconds of the token. Defaults to - 3600 seconds (1 hour). - :param dict attributes: Extra attributes to pass into the token. - """ - - return self._generate_token( - ttl, - { - 'account_sid': self.account_sid, - 'channel': self.worker_sid, - 'worker_sid': self.worker_sid, - 'workspace_sid': self.workspace_sid, - } - ) - - def _generate_token(self, ttl, attributes=None): - payload = { - 'version': self.version, - 'friendly_name': self.worker_sid, - 'policies': self.policies, - 'iss': self.account_sid, - 'exp': int(time.time()) + ttl, - } - - if attributes is not None: - payload.update(attributes) - - return jwt.encode(payload, self.auth_token, 'HS256') - - -def make_policy(url, method, query_filter=None, post_filter=None, - allowed=True): - """ - Create a policy dictionary for the given resource and method. - - :param str url: the resource URL to grant or deny access to - :param str method: the HTTP method to allow or deny - :param dict query_filter: specific GET parameter names to require or allow - :param dict post_filter: POST parameter names to require or allow - :param allowed bool: whether this request is allowed - """ - - return { - 'url': url, - 'method': method, - 'allow': allowed, - 'query_filter': query_filter or {}, - 'post_filter': post_filter or {}, - } diff --git a/twilio/task_router/capability/__init__.py b/twilio/task_router/capability/__init__.py new file mode 100644 index 0000000000..73e66978ef --- /dev/null +++ b/twilio/task_router/capability/__init__.py @@ -0,0 +1,10 @@ +from .capability_api import ( + CapabilityAPI +) + +from .task_router_capability import ( + TaskRouterCapability, + TaskRouterWorkerCapability, + TaskRouterTaskQueueCapability, + TaskRouterWorkspaceCapability +) diff --git a/twilio/task_router/capability/capability_api.py b/twilio/task_router/capability/capability_api.py new file mode 100644 index 0000000000..af1a9bf4ed --- /dev/null +++ b/twilio/task_router/capability/capability_api.py @@ -0,0 +1,68 @@ +import time + +from .. import jwt + + +class CapabilityAPI(object): + """ + A token to control permissions for the TaskRouter service. + + :param str account_sid: The account to generate a token for + :param str auth_token: The auth token for the account. Used to sign the + token and will not be included in generated output. + :param str workspace_sid: The workspace to grant capabilities over + :param str worker_sid: The worker sid to grant capabilities over + :param str base_url: The base TaskRouter API URL + :param str base_ws_url: The base TaskRouter event stream URL + """ + def __init__(self, account_sid, auth_token, version, friendly_name): + self.account_sid = account_sid + self.auth_token = auth_token + + self.version = version + self.friendly_name = friendly_name; + self.policies = [] + + def add_policy(self, url, method, allowed, query_filter = None, post_filter = None): + policy = self.make_policy(url, method, allowed, query_filter, post_filter) + self.policies.append(policy) + + def allow(self, url, method, query_filter = None, post_filter = None): + self.add_policy(url, method, True, query_filter, post_filter) + + def deny(self, url, method, query_filter = None, post_filter = None): + self.add_policy(url, method, False, query_filter, post_filter) + + def generate_token(self, ttl = 3600, attributes = None): + return self._generate_token(ttl) + + def _generate_token(self, ttl, attributes=None): + payload = { + 'iss': self.account_sid, + 'exp': int(time.time()) + ttl, + 'version': self.version, + 'friendly_name': self.friendly_name, + 'policies': self.policies, + } + + if attributes is not None: + payload.update(attributes) + + return jwt.encode(payload, self.auth_token, 'HS256') + + def make_policy(self, url, method, allowed = True, query_filter = None, post_filter = None): + # Create a policy dictionary for the given resource and method. + + # :param str url: the resource URL to grant or deny access to + # :param str method: the HTTP method to allow or deny + # :param allowed bool: whether this request is allowed + # :param dict query_filter: specific GET parameter names to require or allow + # :param dict post_filter: POST parameter names to require or allow + + return { + 'url': url, + 'method': method, + 'allowed': allowed, + 'query_filter': query_filter or {}, + 'post_filter': post_filter or {} + } \ No newline at end of file diff --git a/twilio/task_router/capability/task_router_capability.py b/twilio/task_router/capability/task_router_capability.py new file mode 100644 index 0000000000..c6f69b392f --- /dev/null +++ b/twilio/task_router/capability/task_router_capability.py @@ -0,0 +1,184 @@ +from .capability_api import CapabilityAPI + +import warnings +warnings.simplefilter('always', DeprecationWarning) + +TASK_ROUTER_BASE_URL = 'https://taskrouter.twilio.com' +TASK_ROUTER_BASE_EVENTS_URL = 'https://event-bridge.twilio.com/v1/wschannels' +TASK_ROUTER_VERSION = "v1" + +REQUIRED = {'required': True} +OPTIONAL = {'required': False} + +def deprecated(func): + def log_warning(*args, **kwargs): + # stacklevel = 2 makes the warning refer to the caller of the deprecation rather than the source of deprecation itself + warnings.warn("Call to deprecated function {}.".format(func.__name__), stacklevel = 2, category = DeprecationWarning) + return func(*args, **kwargs) + return log_warning + + +class TaskRouterCapability(CapabilityAPI): + def __init__(self, account_sid, auth_token, workspace_sid, channel_id): + super(TaskRouterCapability, self).__init__(account_sid, auth_token, TASK_ROUTER_VERSION, channel_id) + + self.workspace_sid = workspace_sid + self.channel_id = channel_id + self.base_url = TASK_ROUTER_BASE_URL + "/" + TASK_ROUTER_VERSION + "/Workspaces/" + workspace_sid + + # validate the JWT + self.validate_jwt() + + # set up resources + self.setup_resource() + + # add permissions to GET and POST to the event-bridge channel + self.allow_web_sockets(channel_id) + + # add permissions to fetch the instance resource + self.add_policy(self.resource_url, "GET", True) + + def setup_resource(self): + if self.channel_id[0:2] == "WS": + self.resource_url = self.base_url + elif self.channel_id[0:2] == "WK": + self.resource_url = self.base_url + "/Workers/" + self.channel_id + activity_url = self.base_url + "/Activities" + self.allow(activity_url, "GET") + elif self.channel_id[0:2] == "WQ": + self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id + + def allow_web_sockets(self, channel_id): + web_socket_url = TASK_ROUTER_BASE_EVENTS_URL + "/" + self.account_sid + "/" + self.channel_id; + self.policies.append(self.make_policy(web_socket_url, "GET", True)) + self.policies.append(self.make_policy(web_socket_url, "POST", True)) + + def validate_jwt(self): + if self.account_sid is None or self.account_sid[0:2] != "AC": + raise ValueError('Invalid AccountSid provided: ' + self.account_sid) + if self.workspace_sid is None or self.workspace_sid[0:2] != "WS": + raise ValueError('Invalid WorkspaceSid provided: ' + self.workspace_sid) + if self.channel_id is None: + raise ValueError('ChannelId not provided') + + prefix = self.channel_id[0:2] + if prefix != "WS" and prefix != "WK" and prefix != "WQ": + raise ValueError('Invalid ChannelId provided: ' + self.channel_id) + + def allow_fetch_subresources(self): + self.allow(self.resource_url + "/**", "GET") + + def allow_updates(self): + self.allow(self.resource_url, "POST") + + def allow_updates_subresources(self): + self.allow(self.resource_url + "/**", "POST") + + def allow_delete(self): + self.allow(self.resource_url, "DELETE") + + def allow_delete_subresources(self): + self.allow(self.resource_url + "/**", "DELETE") + + @deprecated + def allow_worker_fetch_attributes(self): + if self.channel_id[0:2] == "WK": + self.policies.append(self.make_policy( + self.resource_url, + 'GET' + ) + ) + else: + raise ValueError("Deprecated function not applicable to non Worker") + + @deprecated + def allow_worker_activity_updates(self): + if self.channel_id[0:2] == "WK": + self.policies.append(self.make_policy( + self.resource_url, + 'POST', + True, + post_filter = {'ActivitySid': REQUIRED} + ) + ) + else: + raise ValueError("Deprecated function not applicable to non Worker") + + + @deprecated + def allow_task_reservation_updates(self): + if self.channel_id[0:2] == "WK": + tasks_url = self.base_url + "/Tasks/**" + self.policies.append(self.make_policy( + tasks_url, + 'POST', + True, + post_filter = {'ReservationStatus': REQUIRED}, + ) + ) + else: + raise ValueError("Deprecated function not applicable to non Worker") + + def get_resource_url(self): + return self.resource_url + + def generate_token(self, ttl = 3600): + task_router_attributes = {} + task_router_attributes["account_sid"] = self.account_sid + task_router_attributes["workspace_sid"] = self.workspace_sid + task_router_attributes["channel"] = self.channel_id + + if self.channel_id[0:2] == "WK": + task_router_attributes["worker_sid"] = self.channel_id + elif self.channel_id[0:2] == "WQ": + task_router_attributes["taskqueue_sid"] = self.channel_id + + return self._generate_token(ttl, task_router_attributes) + +class TaskRouterWorkerCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid, worker_sid): + super(TaskRouterWorkerCapability, self).__init__(account_sid, auth_token, workspace_sid, worker_sid) + + self.reservations_url = self.base_url + "/Tasks/**" + self.activity_url = self.base_url + "/Activities" + + # add permissions to fetch the list of activities and list of worker reservations + self.allow(self.reservations_url, "GET") + self.allow(self.activity_url, "GET") + + def setup_resource(self): + self.resource_url = self.base_url + "/Workers/" + self.channel_id + + def allow_activity_updates(self): + self.policies.append(self.make_policy( + self.resource_url, + 'POST', + True, + post_filter = {'ActivitySid': REQUIRED} + ) + ) + def allow_reservation_updates(self): + self.policies.append(self.make_policy( + self.reservations_url, + 'POST', + True, + post_filter = {'ReservationStatus': REQUIRED}, + ) + ) + +class TaskRouterTaskQueueCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid, taskqueue_sid): + super(TaskRouterTaskQueueCapability, self).__init__(account_sid, auth_token, workspace_sid, taskqueue_sid) + + def setup_resource(self): + self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id + + +class TaskRouterWorkspaceCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid): + super(TaskRouterWorkspaceCapability, self).__init__(account_sid, auth_token, workspace_sid, workspace_sid) + + def setup_resource(self): + self.resource_url = self.base_url + + From 73f40e5778ef44894a6da3c66b6d52277906f52e Mon Sep 17 00:00:00 2001 From: Jen Li Date: Fri, 26 Jun 2015 15:16:45 -0700 Subject: [PATCH 02/13] changed __init__.py file --- twilio/task_router/__init__.py | 10 ++++++++++ twilio/task_router/capability/__init__.py | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 twilio/task_router/__init__.py delete mode 100644 twilio/task_router/capability/__init__.py diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py new file mode 100644 index 0000000000..cf486bcc35 --- /dev/null +++ b/twilio/task_router/__init__.py @@ -0,0 +1,10 @@ +from .. import jwt +import time + +from .capability import ( + CapabilityAPI, + TaskRouterCapability, + TaskRouterWorkerCapability, + TaskRouterTaskQueueCapability, + TaskRouterWorkspaceCapability +) \ No newline at end of file diff --git a/twilio/task_router/capability/__init__.py b/twilio/task_router/capability/__init__.py deleted file mode 100644 index 73e66978ef..0000000000 --- a/twilio/task_router/capability/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .capability_api import ( - CapabilityAPI -) - -from .task_router_capability import ( - TaskRouterCapability, - TaskRouterWorkerCapability, - TaskRouterTaskQueueCapability, - TaskRouterWorkspaceCapability -) From 55c41884ac46a54a62401353824f554f0afab688 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Fri, 26 Jun 2015 15:59:51 -0700 Subject: [PATCH 03/13] no reservation status --- tests/task_router/test_task_router_worker_capability.py | 4 ++-- twilio/task_router/capability/task_router_capability.py | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index 030190747d..c36014b303 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -132,7 +132,7 @@ def test_allow_activity_updates(self): self.assertTrue(policy["allowed"]) self.assertIsNotNone(policy['post_filter']) self.assertEqual({}, policy['query_filter']) - self.assertTrue(policy['post_filter']['ActivitySid']) + self.assertEqual({}, policy['post_filter']) def test_allow_reservation_updates(self): # allow reservation updates @@ -156,7 +156,7 @@ def test_allow_reservation_updates(self): self.assertTrue(policy["allowed"]) self.assertIsNotNone(policy["post_filter"]) self.assertEqual({}, policy["query_filter"]) - self.assertTrue(policy["post_filter"]["ReservationStatus"]) + self.assertEqual({}, policy['post_filter']) if __name__ == "__main__": unittest.main() diff --git a/twilio/task_router/capability/task_router_capability.py b/twilio/task_router/capability/task_router_capability.py index c6f69b392f..f4ecf9d03e 100644 --- a/twilio/task_router/capability/task_router_capability.py +++ b/twilio/task_router/capability/task_router_capability.py @@ -153,16 +153,14 @@ def allow_activity_updates(self): self.policies.append(self.make_policy( self.resource_url, 'POST', - True, - post_filter = {'ActivitySid': REQUIRED} + True ) ) def allow_reservation_updates(self): self.policies.append(self.make_policy( self.reservations_url, 'POST', - True, - post_filter = {'ReservationStatus': REQUIRED}, + True ) ) From b37a9c1bae635bacbac9c8fcce69a5d02a25f77a Mon Sep 17 00:00:00 2001 From: Jen Li Date: Fri, 26 Jun 2015 16:01:54 -0700 Subject: [PATCH 04/13] wrong reservation status changed --- twilio/task_router/capability/task_router_capability.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/twilio/task_router/capability/task_router_capability.py b/twilio/task_router/capability/task_router_capability.py index f4ecf9d03e..e5a6d5e3e0 100644 --- a/twilio/task_router/capability/task_router_capability.py +++ b/twilio/task_router/capability/task_router_capability.py @@ -113,7 +113,6 @@ def allow_task_reservation_updates(self): tasks_url, 'POST', True, - post_filter = {'ReservationStatus': REQUIRED}, ) ) else: @@ -153,7 +152,8 @@ def allow_activity_updates(self): self.policies.append(self.make_policy( self.resource_url, 'POST', - True + True, + post_filter = {'ActivitySid': REQUIRED} ) ) def allow_reservation_updates(self): From 7f987b13951a2bd9466eaf428792dc8c4fde5680 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Mon, 29 Jun 2015 16:59:24 -0700 Subject: [PATCH 05/13] bug fix to fetch reservations --- .../test_task_router_capability.py | 42 +++++++++++++------ .../test_task_router_worker_capability.py | 3 +- .../capability/task_router_capability.py | 5 +++ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 35b1cb7678..d700fd44c6 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -9,7 +9,7 @@ class TaskRouterCapabilityTest(unittest.TestCase): - def test_workspace_default(self): + def test_workspace_default(self): account_sid = "AC123" auth_token = "foobar" workspace_sid = "WS456" @@ -58,7 +58,7 @@ def test_workspace_default(self): self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) - def test_worker_default(self): + def test_worker_default(self): account_sid = "AC123" auth_token = "foobar" workspace_sid = "WS456" @@ -82,7 +82,7 @@ def test_worker_default(self): self.assertEqual(decoded["friendly_name"], worker_sid) policies = decoded['policies'] - self.assertEqual(len(policies), 4) + self.assertEqual(len(policies), 5) # activity GET fetch_activity = policies[0] @@ -92,8 +92,16 @@ def test_worker_default(self): self.assertEqual({}, fetch_activity['query_filter']) self.assertEqual({}, fetch_activity['post_filter']) + # reservation GET + fetch_reservation = policies[1] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) + self.assertEqual("GET", fetch_reservation['method']) + self.assertTrue(fetch_reservation['allowed']) + self.assertEqual({}, fetch_reservation['query_filter']) + self.assertEqual({}, fetch_reservation['post_filter']) + # websocket GET - get_policy = policies[1] + get_policy = policies[2] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) self.assertEqual("GET", get_policy['method']) self.assertTrue(get_policy['allowed']) @@ -101,7 +109,7 @@ def test_worker_default(self): self.assertEqual({}, get_policy['post_filter']) # websocket POST - post_policy = policies[2] + post_policy = policies[3] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) self.assertEqual("POST", post_policy['method']) self.assertTrue(post_policy['allowed']) @@ -109,14 +117,14 @@ def test_worker_default(self): self.assertEqual({}, post_policy['post_filter']) # fetch GET - fetch_policy = policies[3] + fetch_policy = policies[4] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) self.assertTrue(fetch_policy['allowed']) self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) - def test_task_queue_default(self): + def test_task_queue_default(self): account_sid = "AC123" auth_token = "foobar" workspace_sid = "WS456" @@ -190,9 +198,9 @@ def test_deprecated_worker(self): self.assertEqual(decoded["friendly_name"], worker_sid) policies = decoded['policies'] - self.assertEqual(len(policies), 4) + self.assertEqual(len(policies), 5) - # should expect 4 policies + # should expect 5 policies # activity GET fetch_activity = policies[0] @@ -202,8 +210,16 @@ def test_deprecated_worker(self): self.assertEqual({}, fetch_activity['query_filter']) self.assertEqual({}, fetch_activity['post_filter']) + # reservation GET + fetch_reservation = policies[1] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) + self.assertEqual("GET", fetch_reservation['method']) + self.assertTrue(fetch_reservation['allowed']) + self.assertEqual({}, fetch_reservation['query_filter']) + self.assertEqual({}, fetch_reservation['post_filter']) + # websocket GET - get_policy = policies[1] + get_policy = policies[2] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) self.assertEqual("GET", get_policy['method']) self.assertTrue(get_policy['allowed']) @@ -211,7 +227,7 @@ def test_deprecated_worker(self): self.assertEqual({}, get_policy['post_filter']) # websocket POST - post_policy = policies[2] + post_policy = policies[3] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) self.assertEqual("POST", post_policy['method']) self.assertTrue(post_policy['allowed']) @@ -219,7 +235,7 @@ def test_deprecated_worker(self): self.assertEqual({}, post_policy['post_filter']) # fetch GET - fetch_policy = policies[3] + fetch_policy = policies[4] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) self.assertTrue(fetch_policy['allowed']) @@ -250,4 +266,4 @@ def test_deprecated_worker(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index c36014b303..ecd9509cb1 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -1,5 +1,4 @@ import sys - import time import unittest import warnings @@ -132,7 +131,7 @@ def test_allow_activity_updates(self): self.assertTrue(policy["allowed"]) self.assertIsNotNone(policy['post_filter']) self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.assertTrue(policy['post_filter']['ActivitySid']) def test_allow_reservation_updates(self): # allow reservation updates diff --git a/twilio/task_router/capability/task_router_capability.py b/twilio/task_router/capability/task_router_capability.py index e5a6d5e3e0..6758020af6 100644 --- a/twilio/task_router/capability/task_router_capability.py +++ b/twilio/task_router/capability/task_router_capability.py @@ -43,8 +43,13 @@ def setup_resource(self): self.resource_url = self.base_url elif self.channel_id[0:2] == "WK": self.resource_url = self.base_url + "/Workers/" + self.channel_id + activity_url = self.base_url + "/Activities" self.allow(activity_url, "GET") + + reservations_url = self.base_url + "/Tasks/**" + self.allow(reservations_url, "GET") + elif self.channel_id[0:2] == "WQ": self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id From 7be91635b64092b22c0b51d474429200511cfe10 Mon Sep 17 00:00:00 2001 From: Justin Witz Date: Wed, 15 Jul 2015 09:44:47 -0700 Subject: [PATCH 06/13] Remove CapabilityAPI Fix formatting problems (whitespaces at end of lines, line length of 80 chars, two spaces before class names, new lines at end of file, no spaces between default parameter attributes,) Fix old capability test --- tests/task_router/test_capability.py | 24 +- .../test_task_router_capability.py | 39 ++- .../test_task_router_taskqueue_capability.py | 184 +++++------ .../test_task_router_worker_capability.py | 302 +++++++++--------- .../test_task_router_workspace_capability.py | 181 ++++++----- twilio/task_router/__init__.py | 255 ++++++++++++++- .../task_router/capability/capability_api.py | 68 ---- .../capability/task_router_capability.py | 187 ----------- 8 files changed, 617 insertions(+), 623 deletions(-) delete mode 100644 twilio/task_router/capability/capability_api.py delete mode 100644 twilio/task_router/capability/task_router_capability.py diff --git a/tests/task_router/test_capability.py b/tests/task_router/test_capability.py index abfb25b0f5..707fe97f83 100644 --- a/tests/task_router/test_capability.py +++ b/tests/task_router/test_capability.py @@ -59,6 +59,22 @@ def test_defaults(self): (self.account_sid, self.worker_sid) ) expected = [ + { + 'url': + 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities', + 'method': 'GET', + 'allow': True, + 'query_filter': {}, + 'post_filter': {}, + }, + { + 'url': 'https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**' % + (self.workspace_sid), + 'method': 'GET', + 'allow': True, + 'query_filter': {}, + 'post_filter': {}, + }, { 'url': websocket_url, 'method': 'GET', @@ -74,13 +90,13 @@ def test_defaults(self): 'post_filter': {}, }, { - 'url': - 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities', + 'url': 'https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s' % + (self.workspace_sid, self.worker_sid), 'method': 'GET', 'allow': True, 'query_filter': {}, 'post_filter': {}, - }, + } ] self.assertEqual(expected, decoded['policies']) @@ -140,6 +156,6 @@ def test_allow_task_reservation_updates(self): 'method': 'POST', 'allow': True, 'query_filter': {}, - 'post_filter': {'ReservationStatus': {'required': True}}, + 'post_filter': {}, } self.assertEqual(expected, decoded['policies'][-1]) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index d700fd44c6..9cbe90c1aa 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -1,11 +1,9 @@ -import sys - -import time import unittest import warnings from twilio import jwt -from twilio.task_router.capability import TaskRouterCapability +from twilio.task_router import TaskRouterCapability + class TaskRouterCapabilityTest(unittest.TestCase): @@ -38,7 +36,7 @@ def test_workspace_default(self): get_policy = policies[0] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) + self.assertTrue(get_policy['allow']) self.assertEqual({}, get_policy['query_filter']) self.assertEqual({}, get_policy['post_filter']) @@ -46,7 +44,7 @@ def test_workspace_default(self): post_policy = policies[1] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) + self.assertTrue(post_policy['allow']) self.assertEqual({}, post_policy['query_filter']) self.assertEqual({}, post_policy['post_filter']) @@ -54,7 +52,7 @@ def test_workspace_default(self): fetch_policy = policies[2] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) + self.assertTrue(fetch_policy['allow']) self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) @@ -88,7 +86,7 @@ def test_worker_default(self): fetch_activity = policies[0] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) self.assertEqual("GET", fetch_activity['method']) - self.assertTrue(fetch_activity['allowed']) + self.assertTrue(fetch_activity['allow']) self.assertEqual({}, fetch_activity['query_filter']) self.assertEqual({}, fetch_activity['post_filter']) @@ -96,7 +94,7 @@ def test_worker_default(self): fetch_reservation = policies[1] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) self.assertEqual("GET", fetch_reservation['method']) - self.assertTrue(fetch_reservation['allowed']) + self.assertTrue(fetch_reservation['allow']) self.assertEqual({}, fetch_reservation['query_filter']) self.assertEqual({}, fetch_reservation['post_filter']) @@ -104,7 +102,7 @@ def test_worker_default(self): get_policy = policies[2] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) + self.assertTrue(get_policy['allow']) self.assertEqual({}, get_policy['query_filter']) self.assertEqual({}, get_policy['post_filter']) @@ -112,7 +110,7 @@ def test_worker_default(self): post_policy = policies[3] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) + self.assertTrue(post_policy['allow']) self.assertEqual({}, post_policy['query_filter']) self.assertEqual({}, post_policy['post_filter']) @@ -120,7 +118,7 @@ def test_worker_default(self): fetch_policy = policies[4] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) + self.assertTrue(fetch_policy['allow']) self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) @@ -154,7 +152,7 @@ def test_task_queue_default(self): get_policy = policies[0] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) + self.assertTrue(get_policy['allow']) self.assertEqual({}, get_policy['query_filter']) self.assertEqual({}, get_policy['post_filter']) @@ -162,7 +160,7 @@ def test_task_queue_default(self): post_policy = policies[1] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) + self.assertTrue(post_policy['allow']) self.assertEqual({}, post_policy['query_filter']) self.assertEqual({}, post_policy['post_filter']) @@ -170,7 +168,7 @@ def test_task_queue_default(self): fetch_policy = policies[2] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) + self.assertTrue(fetch_policy['allow']) self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) @@ -206,7 +204,7 @@ def test_deprecated_worker(self): fetch_activity = policies[0] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) self.assertEqual("GET", fetch_activity['method']) - self.assertTrue(fetch_activity['allowed']) + self.assertTrue(fetch_activity['allow']) self.assertEqual({}, fetch_activity['query_filter']) self.assertEqual({}, fetch_activity['post_filter']) @@ -214,7 +212,7 @@ def test_deprecated_worker(self): fetch_reservation = policies[1] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) self.assertEqual("GET", fetch_reservation['method']) - self.assertTrue(fetch_reservation['allowed']) + self.assertTrue(fetch_reservation['allow']) self.assertEqual({}, fetch_reservation['query_filter']) self.assertEqual({}, fetch_reservation['post_filter']) @@ -222,7 +220,7 @@ def test_deprecated_worker(self): get_policy = policies[2] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) + self.assertTrue(get_policy['allow']) self.assertEqual({}, get_policy['query_filter']) self.assertEqual({}, get_policy['post_filter']) @@ -230,7 +228,7 @@ def test_deprecated_worker(self): post_policy = policies[3] self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) + self.assertTrue(post_policy['allow']) self.assertEqual({}, post_policy['query_filter']) self.assertEqual({}, post_policy['post_filter']) @@ -238,7 +236,7 @@ def test_deprecated_worker(self): fetch_policy = policies[4] self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) + self.assertTrue(fetch_policy['allow']) self.assertEqual({}, fetch_policy['query_filter']) self.assertEqual({}, fetch_policy['post_filter']) @@ -264,6 +262,5 @@ def test_deprecated_worker(self): assert issubclass(w[-1].category, DeprecationWarning) assert "deprecated" in str(w[-1].message) - if __name__ == "__main__": unittest.main() diff --git a/tests/task_router/test_task_router_taskqueue_capability.py b/tests/task_router/test_task_router_taskqueue_capability.py index bd3cec6295..66f466a763 100644 --- a/tests/task_router/test_task_router_taskqueue_capability.py +++ b/tests/task_router/test_task_router_taskqueue_capability.py @@ -1,132 +1,132 @@ -import sys import time import unittest from twilio import jwt -from twilio.task_router.capability import TaskRouterTaskQueueCapability +from twilio.task_router import TaskRouterTaskQueueCapability + class TaskRouterTaskQueueCapabilityTest(unittest.TestCase): - def setUp(self): - self.account_sid = "AC123" - self.auth_token = "foobar" - self.workspace_sid = "WS456" - self.taskqueue_sid = "WQ789" - self.capability = TaskRouterTaskQueueCapability(self.account_sid, self.auth_token, self.workspace_sid, self.taskqueue_sid) + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.taskqueue_sid = "WQ789" + self.capability = TaskRouterTaskQueueCapability(self.account_sid, self.auth_token, self.workspace_sid, self.taskqueue_sid) - def test_generate_token(self): + def test_generate_token(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], self.account_sid) - self.assertEqual(decoded["account_sid"], self.account_sid) - self.assertEqual(decoded["workspace_sid"], self.workspace_sid) - self.assertEqual(decoded["taskqueue_sid"], self.taskqueue_sid) - self.assertEqual(decoded["channel"], self.taskqueue_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], self.taskqueue_sid) + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["taskqueue_sid"], self.taskqueue_sid) + self.assertEqual(decoded["channel"], self.taskqueue_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.taskqueue_sid) - def test_generate_token_with_default_ttl(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) - def test_generate_token_with_custom_ttl(self): - ttl = 10000 + def test_generate_token_with_custom_ttl(self): + ttl = 10000 - token = self.capability.generate_token(ttl) - self.assertIsNotNone(token) + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) - def test_default(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + def test_default(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 3) + policies = decoded['policies'] + self.assertEqual(len(policies), 3) - # websocket GET - get_policy = policies[0] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allow']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) - # websocket POST - post_policy = policies[1] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allow']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) - # fetch GET - fetch_policy = policies[2] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allow']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) - def test_allow_fetch_subresources(self): - self.capability.allow_fetch_subresources() + def test_allow_fetch_subresources(self): + self.capability.allow_fetch_subresources() - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 4) + policies = decoded['policies'] + self.assertEqual(len(policies), 4) - # confirm the additional policy generated with allow_fetch_subresources() + # confirm the additional policy generated with allow_fetch_subresources() - policy = policies[3] + policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") - self.assertEqual(policy['method'], "GET") - self.assertTrue(policy['allowed']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") + self.assertEqual(policy['method'], "GET") + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) - def test_allow_updates_subresources(self): - self.capability.allow_updates_subresources() + def test_allow_updates_subresources(self): + self.capability.allow_updates_subresources() - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 4) + policies = decoded['policies'] + self.assertEqual(len(policies), 4) - # confirm the additional policy generated with allow_updates_subresources() + # confirm the additional policy generated with allow_updates_subresources() - policy = policies[3] + policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") - self.assertEqual(policy['method'], "POST") - self.assertTrue(policy['allowed']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789/**") + self.assertEqual(policy['method'], "POST") + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) if __name__ == "__main__": - unittest.main() + unittest.main() diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index ecd9509cb1..35abb5b831 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -1,161 +1,159 @@ -import sys import time import unittest -import warnings from twilio import jwt -from twilio.task_router.capability import TaskRouterWorkerCapability +from twilio.task_router import TaskRouterWorkerCapability + class TaskRouterWorkerCapabilityTest(unittest.TestCase): - def setUp(self): - self.account_sid = "AC123" - self.auth_token = "foobar" - self.workspace_sid = "WS456" - self.worker_sid = "WK789" - self.capability = TaskRouterWorkerCapability(self.account_sid, self.auth_token, self.workspace_sid, self.worker_sid) - - def test_generate_token(self): - - token = self.capability.generate_token() - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - self.assertEqual(decoded["iss"], self.account_sid) - self.assertEqual(decoded["account_sid"], self.account_sid) - self.assertEqual(decoded["workspace_sid"], self.workspace_sid) - self.assertEqual(decoded["worker_sid"], self.worker_sid) - self.assertEqual(decoded["channel"], self.worker_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], self.worker_sid) - - def test_generate_token_with_default_ttl(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - self.assertEqual(int(time.time()) + 3600, decoded["exp"]) - - def test_generate_token_with_custom_ttl(self): - ttl = 10000 - - token = self.capability.generate_token(ttl) - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - self.assertEqual(int(time.time()) + 10000, decoded["exp"]) - - def test_defaults(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - websocket_url = 'https://event-bridge.twilio.com/v1/wschannels/%s/%s' % (self.account_sid, self.worker_sid) - - # expect 5 policies - policies = decoded['policies'] - self.assertEqual(len(policies), 5) - - # policy 0 - GET websocket - get_policy = policies[0] - self.assertIsNotNone(get_policy) - self.assertEqual(get_policy['url'], websocket_url) - self.assertEqual(get_policy['method'], 'GET') - self.assertTrue(get_policy['allowed']) - self.assertEqual(get_policy['query_filter'], {}) - self.assertEqual(get_policy['post_filter'], {}) - - # policy 1 - POST - post_policy = policies[1] - self.assertIsNotNone(post_policy) - self.assertEqual(post_policy['url'], websocket_url) - self.assertEqual(post_policy['method'], 'POST') - self.assertTrue(post_policy['allowed']) - self.assertEqual(post_policy['query_filter'], {}) - self.assertEqual(post_policy['post_filter'], {}) - - # policy 2 - Worker fetch - worker_fetch_policy = policies[2] - self.assertIsNotNone(worker_fetch_policy) - self.assertEqual(worker_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789') - self.assertEqual(worker_fetch_policy['method'], 'GET') - self.assertTrue(worker_fetch_policy['allowed']) - self.assertEqual(worker_fetch_policy['query_filter'], {}) - self.assertEqual(worker_fetch_policy['post_filter'], {}) - - # policy 3 - Reservation fetch - reservation_fetch_policy = policies[3] - self.assertIsNotNone(reservation_fetch_policy) - self.assertEqual(reservation_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**') - self.assertEqual(reservation_fetch_policy['method'], 'GET') - self.assertTrue(reservation_fetch_policy['allowed']) - self.assertEqual(reservation_fetch_policy['query_filter'], {}) - self.assertEqual(reservation_fetch_policy['post_filter'], {}) - - # policy 4 - Activity fetch - activity_fetch_policy = policies[4] - self.assertIsNotNone(activity_fetch_policy) - self.assertEqual(activity_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities') - self.assertEqual(activity_fetch_policy['method'], 'GET') - self.assertTrue(activity_fetch_policy['allowed']) - self.assertEqual(activity_fetch_policy['query_filter'], {}) - self.assertEqual(activity_fetch_policy['post_filter'], {}) - - def test_allow_activity_updates(self): - - # allow activity updates to the worker - self.capability.allow_activity_updates() - - token = self.capability.generate_token() - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - policies = decoded['policies'] - self.assertEqual(len(policies), 6) - policy = policies[5] - - url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s" % (self.workspace_sid, self.worker_sid) - - self.assertEqual(url, policy["url"]) - self.assertEqual("POST", policy["method"]) - self.assertTrue(policy["allowed"]) - self.assertIsNotNone(policy['post_filter']) - self.assertEqual({}, policy['query_filter']) - self.assertTrue(policy['post_filter']['ActivitySid']) - - def test_allow_reservation_updates(self): - # allow reservation updates - self.capability.allow_reservation_updates() - - token = self.capability.generate_token() - self.assertIsNotNone(token) - - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) - - policies = decoded['policies'] - self.assertEqual(len(policies), 6) - - policy = policies[5] - - url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**" % self.workspace_sid - - self.assertEqual(url, policy["url"]) - self.assertEqual("POST", policy["method"]) - self.assertTrue(policy["allowed"]) - self.assertIsNotNone(policy["post_filter"]) - self.assertEqual({}, policy["query_filter"]) - self.assertEqual({}, policy['post_filter']) + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.worker_sid = "WK789" + self.capability = TaskRouterWorkerCapability(self.account_sid, self.auth_token, self.workspace_sid, self.worker_sid) + + def test_generate_token(self): + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["worker_sid"], self.worker_sid) + self.assertEqual(decoded["channel"], self.worker_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.worker_sid) + + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + + def test_generate_token_with_custom_ttl(self): + ttl = 10000 + + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + + def test_defaults(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + websocket_url = 'https://event-bridge.twilio.com/v1/wschannels/%s/%s' % (self.account_sid, self.worker_sid) + + # expect 5 policies + policies = decoded['policies'] + self.assertEqual(len(policies), 5) + + # policy 0 - GET websocket + get_policy = policies[0] + self.assertIsNotNone(get_policy) + self.assertEqual(get_policy['url'], websocket_url) + self.assertEqual(get_policy['method'], 'GET') + self.assertTrue(get_policy['allow']) + self.assertEqual(get_policy['query_filter'], {}) + self.assertEqual(get_policy['post_filter'], {}) + + # policy 1 - POST + post_policy = policies[1] + self.assertIsNotNone(post_policy) + self.assertEqual(post_policy['url'], websocket_url) + self.assertEqual(post_policy['method'], 'POST') + self.assertTrue(post_policy['allow']) + self.assertEqual(post_policy['query_filter'], {}) + self.assertEqual(post_policy['post_filter'], {}) + + # policy 2 - Worker fetch + worker_fetch_policy = policies[2] + self.assertIsNotNone(worker_fetch_policy) + self.assertEqual(worker_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789') + self.assertEqual(worker_fetch_policy['method'], 'GET') + self.assertTrue(worker_fetch_policy['allow']) + self.assertEqual(worker_fetch_policy['query_filter'], {}) + self.assertEqual(worker_fetch_policy['post_filter'], {}) + + # policy 3 - Reservation fetch + reservation_fetch_policy = policies[3] + self.assertIsNotNone(reservation_fetch_policy) + self.assertEqual(reservation_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**') + self.assertEqual(reservation_fetch_policy['method'], 'GET') + self.assertTrue(reservation_fetch_policy['allow']) + self.assertEqual(reservation_fetch_policy['query_filter'], {}) + self.assertEqual(reservation_fetch_policy['post_filter'], {}) + + # policy 4 - Activity fetch + activity_fetch_policy = policies[4] + self.assertIsNotNone(activity_fetch_policy) + self.assertEqual(activity_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities') + self.assertEqual(activity_fetch_policy['method'], 'GET') + self.assertTrue(activity_fetch_policy['allow']) + self.assertEqual(activity_fetch_policy['query_filter'], {}) + self.assertEqual(activity_fetch_policy['post_filter'], {}) + + def test_allow_activity_updates(self): + + # allow activity updates to the worker + self.capability.allow_activity_updates() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 6) + policy = policies[5] + + url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s" % (self.workspace_sid, self.worker_sid) + + self.assertEqual(url, policy["url"]) + self.assertEqual("POST", policy["method"]) + self.assertTrue(policy["allow"]) + self.assertIsNotNone(policy['post_filter']) + self.assertEqual({}, policy['query_filter']) + self.assertTrue(policy['post_filter']['ActivitySid']) + + def test_allow_reservation_updates(self): + # allow reservation updates + self.capability.allow_reservation_updates() + + token = self.capability.generate_token() + self.assertIsNotNone(token) + + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) + + policies = decoded['policies'] + self.assertEqual(len(policies), 6) + + policy = policies[5] + + url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**" % self.workspace_sid + + self.assertEqual(url, policy["url"]) + self.assertEqual("POST", policy["method"]) + self.assertTrue(policy["allow"]) + self.assertEqual({}, policy["query_filter"]) + self.assertEqual({}, policy['post_filter']) if __name__ == "__main__": - unittest.main() + unittest.main() diff --git a/tests/task_router/test_task_router_workspace_capability.py b/tests/task_router/test_task_router_workspace_capability.py index cc389f7120..b35e692897 100644 --- a/tests/task_router/test_task_router_workspace_capability.py +++ b/tests/task_router/test_task_router_workspace_capability.py @@ -1,131 +1,130 @@ -import sys - import time import unittest from twilio import jwt -from twilio.task_router.capability import TaskRouterWorkspaceCapability +from twilio.task_router import TaskRouterWorkspaceCapability + class TaskRouterWorkspaceCapabilityTest(unittest.TestCase): - def setUp(self): - self.account_sid = "AC123" - self.auth_token = "foobar" - self.workspace_sid = "WS456" - self.capability = TaskRouterWorkspaceCapability(self.account_sid, self.auth_token, self.workspace_sid) + def setUp(self): + self.account_sid = "AC123" + self.auth_token = "foobar" + self.workspace_sid = "WS456" + self.capability = TaskRouterWorkspaceCapability(self.account_sid, self.auth_token, self.workspace_sid) - def test_generate_token(self): + def test_generate_token(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], self.account_sid) - self.assertEqual(decoded["account_sid"], self.account_sid) - self.assertEqual(decoded["workspace_sid"], self.workspace_sid) - self.assertEqual(decoded["channel"], self.workspace_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], self.workspace_sid) + self.assertEqual(decoded["iss"], self.account_sid) + self.assertEqual(decoded["account_sid"], self.account_sid) + self.assertEqual(decoded["workspace_sid"], self.workspace_sid) + self.assertEqual(decoded["channel"], self.workspace_sid) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], self.workspace_sid) - def test_generate_token_with_default_ttl(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + def test_generate_token_with_default_ttl(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(int(time.time()) + 3600, decoded["exp"]) + self.assertEqual(int(time.time()) + 3600, decoded["exp"]) - def test_generate_token_with_custom_ttl(self): - ttl = 10000 + def test_generate_token_with_custom_ttl(self): + ttl = 10000 - token = self.capability.generate_token(ttl) - self.assertIsNotNone(token) + token = self.capability.generate_token(ttl) + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - self.assertEqual(int(time.time()) + 10000, decoded["exp"]) + self.assertEqual(int(time.time()) + 10000, decoded["exp"]) - def test_default(self): - token = self.capability.generate_token() - self.assertIsNotNone(token) + def test_default(self): + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 3) + policies = decoded['policies'] + self.assertEqual(len(policies), 3) - # websocket GET - get_policy = policies[0] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allowed']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) + # websocket GET + get_policy = policies[0] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) + self.assertEqual("GET", get_policy['method']) + self.assertTrue(get_policy['allow']) + self.assertEqual({}, get_policy['query_filter']) + self.assertEqual({}, get_policy['post_filter']) - # websocket POST - post_policy = policies[1] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allowed']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) + # websocket POST + post_policy = policies[1] + self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) + self.assertEqual("POST", post_policy['method']) + self.assertTrue(post_policy['allow']) + self.assertEqual({}, post_policy['query_filter']) + self.assertEqual({}, post_policy['post_filter']) - # fetch GET - fetch_policy = policies[2] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allowed']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + # fetch GET + fetch_policy = policies[2] + self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) + self.assertEqual("GET", fetch_policy['method']) + self.assertTrue(fetch_policy['allow']) + self.assertEqual({}, fetch_policy['query_filter']) + self.assertEqual({}, fetch_policy['post_filter']) - def test_allow_fetch_subresources(self): - self.capability.allow_fetch_subresources() + def test_allow_fetch_subresources(self): + self.capability.allow_fetch_subresources() - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 4) + policies = decoded['policies'] + self.assertEqual(len(policies), 4) - # confirm the additional policy generated with allow_fetch_subresources() + # confirm the additional policy generated with allow_fetch_subresources() - policy = policies[3] + policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") - self.assertEqual(policy['method'], "GET") - self.assertTrue(policy['allowed']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") + self.assertEqual(policy['method'], "GET") + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) - def test_allow_updates_subresources(self): - self.capability.allow_updates_subresources() + def test_allow_updates_subresources(self): + self.capability.allow_updates_subresources() - token = self.capability.generate_token() - self.assertIsNotNone(token) + token = self.capability.generate_token() + self.assertIsNotNone(token) - decoded = jwt.decode(token, self.auth_token) - self.assertIsNotNone(decoded) + decoded = jwt.decode(token, self.auth_token) + self.assertIsNotNone(decoded) - policies = decoded['policies'] - self.assertEqual(len(policies), 4) + policies = decoded['policies'] + self.assertEqual(len(policies), 4) - # confirm the additional policy generated with allow_updates_subresources() + # confirm the additional policy generated with allow_updates_subresources() - policy = policies[3] + policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") - self.assertEqual(policy['method'], "POST") - self.assertTrue(policy['allowed']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") + self.assertEqual(policy['method'], "POST") + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py index cf486bcc35..58a313d5e2 100644 --- a/twilio/task_router/__init__.py +++ b/twilio/task_router/__init__.py @@ -1,10 +1,249 @@ -from .. import jwt import time +from .. import jwt + +import warnings +warnings.simplefilter('always', DeprecationWarning) + +TASK_ROUTER_BASE_URL = 'https://taskrouter.twilio.com' +TASK_ROUTER_BASE_EVENTS_URL = 'https://event-bridge.twilio.com/v1/wschannels' +TASK_ROUTER_VERSION = "v1" + +REQUIRED = {'required': True} +OPTIONAL = {'required': False} + + +def deprecated(func): + def log_warning(*args, **kwargs): + # stacklevel = 2 makes the warning refer to the caller of the + # deprecation rather than the source of deprecation itself + warnings.warn("Call to deprecated function {}.". + format(func.__name__), + stacklevel=2, + category=DeprecationWarning) + return func(*args, **kwargs) + return log_warning + + +class TaskRouterCapability(object): + def __init__(self, account_sid, auth_token, workspace_sid, channel_id): + self.account_sid = account_sid + self.auth_token = auth_token + self.policies = [] + + self.workspace_sid = workspace_sid + self.channel_id = channel_id + self.base_url = (TASK_ROUTER_BASE_URL + "/" + + TASK_ROUTER_VERSION + + "/Workspaces/" + workspace_sid) + + # validate the JWT + self.validate_jwt() + + # set up resources + self.setup_resource() + + # add permissions to GET and POST to the event-bridge channel + self.allow_web_sockets(channel_id) + + # add permissions to fetch the instance resource + self.add_policy(self.resource_url, "GET", True) + + def setup_resource(self): + if self.channel_id[0:2] == "WS": + self.resource_url = self.base_url + elif self.channel_id[0:2] == "WK": + self.resource_url = self.base_url + "/Workers/" + self.channel_id + + activity_url = self.base_url + "/Activities" + self.allow(activity_url, "GET") + + reservations_url = self.base_url + "/Tasks/**" + self.allow(reservations_url, "GET") + + elif self.channel_id[0:2] == "WQ": + self.resource_url = self.base_url + \ + "/TaskQueues/" + self.channel_id + + def allow_web_sockets(self, channel_id): + web_socket_url = TASK_ROUTER_BASE_EVENTS_URL + "/" + \ + self.account_sid + "/" + self.channel_id + + self.policies.append(self.make_policy(web_socket_url, "GET", True)) + self.policies.append(self.make_policy(web_socket_url, "POST", True)) + + def validate_jwt(self): + if self.account_sid is None or self.account_sid[0:2] != "AC": + raise ValueError('Invalid AccountSid provided: ' + + self.account_sid) + if self.workspace_sid is None or self.workspace_sid[0:2] != "WS": + raise ValueError('Invalid WorkspaceSid provided: ' + + self.workspace_sid) + if self.channel_id is None: + raise ValueError('ChannelId not provided') + + prefix = self.channel_id[0:2] + if prefix != "WS" and prefix != "WK" and prefix != "WQ": + raise ValueError('Invalid ChannelId provided: ' + self.channel_id) + + def allow_fetch_subresources(self): + self.allow(self.resource_url + "/**", "GET") + + def allow_updates(self): + self.allow(self.resource_url, "POST") + + def allow_updates_subresources(self): + self.allow(self.resource_url + "/**", "POST") + + def allow_delete(self): + self.allow(self.resource_url, "DELETE") + + def allow_delete_subresources(self): + self.allow(self.resource_url + "/**", "DELETE") + + @deprecated + def allow_worker_fetch_attributes(self): + if self.channel_id[0:2] == "WK": + self.policies.append(self.make_policy( + self.resource_url, + 'GET')) + else: + raise ValueError("Deprecated func not applicable to non Worker") + + @deprecated + def allow_worker_activity_updates(self): + if self.channel_id[0:2] == "WK": + self.policies.append(self.make_policy( + self.resource_url, + 'POST', + True, + post_filter={'ActivitySid': REQUIRED})) + else: + raise ValueError("Deprecated func not applicable to non Worker") + + @deprecated + def allow_task_reservation_updates(self): + if self.channel_id[0:2] == "WK": + tasks_url = self.base_url + "/Tasks/**" + self.policies.append(self.make_policy( + tasks_url, + 'POST', + True)) + else: + raise ValueError("Deprecated func not applicable to non Worker") + + def add_policy(self, url, method, + allowed, query_filter=None, post_filter=None): + + policy = self.make_policy(url, method, + allowed, query_filter, post_filter) + self.policies.append(policy) + + def allow(self, url, method, query_filter=None, post_filter=None): + self.add_policy(url, method, True, query_filter, post_filter) + + def deny(self, url, method, query_filter=None, post_filter=None): + self.add_policy(url, method, False, query_filter, post_filter) + + def make_policy(self, url, method, + allowed=True, query_filter=None, post_filter=None): + + # Create a policy dictionary for the given resource and method. + # :param str url: the resource URL to grant or deny access to + # :param str method: the HTTP method to allow or deny + # :param allowed bool: whether this request is allowed + # :param dict query_filter: specific GET parameter names + # to require or allow + # :param dict post_filter: POST parameter names + # to require or allow + + return { + 'url': url, + 'method': method, + 'allow': allowed, + 'query_filter': query_filter or {}, + 'post_filter': post_filter or {} + } + + def get_resource_url(self): + return self.resource_url + + def generate_token(self, ttl=3600): + task_router_attributes = {} + task_router_attributes["account_sid"] = self.account_sid + task_router_attributes["workspace_sid"] = self.workspace_sid + task_router_attributes["channel"] = self.channel_id + + if self.channel_id[0:2] == "WK": + task_router_attributes["worker_sid"] = self.channel_id + elif self.channel_id[0:2] == "WQ": + task_router_attributes["taskqueue_sid"] = self.channel_id + + return self._generate_token(ttl, task_router_attributes) + + def _generate_token(self, ttl, attributes=None): + payload = { + 'iss': self.account_sid, + 'exp': int(time.time()) + ttl, + 'version': TASK_ROUTER_VERSION, + 'friendly_name': self.channel_id, + 'policies': self.policies, + } + + if attributes is not None: + payload.update(attributes) + + return jwt.encode(payload, self.auth_token, 'HS256') + + +class TaskRouterWorkerCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid, worker_sid): + super(TaskRouterWorkerCapability, self).__init__(account_sid, + auth_token, + workspace_sid, + worker_sid) + + self.reservations_url = self.base_url + "/Tasks/**" + self.activity_url = self.base_url + "/Activities" + + # add permissions to fetch the list of activities and + # list of worker reservations + self.allow(self.reservations_url, "GET") + self.allow(self.activity_url, "GET") + + def setup_resource(self): + self.resource_url = self.base_url + "/Workers/" + self.channel_id + + def allow_activity_updates(self): + self.policies.append(self.make_policy( + self.resource_url, + 'POST', + True, + post_filter={'ActivitySid': REQUIRED})) + + def allow_reservation_updates(self): + self.policies.append(self.make_policy( + self.reservations_url, + 'POST', + True)) + + +class TaskRouterTaskQueueCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid, taskqueue_sid): + super(TaskRouterTaskQueueCapability, self).__init__(account_sid, + auth_token, + workspace_sid, + taskqueue_sid) + + def setup_resource(self): + self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id + + +class TaskRouterWorkspaceCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid): + super(TaskRouterWorkspaceCapability, self).__init__(account_sid, + auth_token, + workspace_sid, + workspace_sid) -from .capability import ( - CapabilityAPI, - TaskRouterCapability, - TaskRouterWorkerCapability, - TaskRouterTaskQueueCapability, - TaskRouterWorkspaceCapability -) \ No newline at end of file + def setup_resource(self): + self.resource_url = self.base_url diff --git a/twilio/task_router/capability/capability_api.py b/twilio/task_router/capability/capability_api.py deleted file mode 100644 index af1a9bf4ed..0000000000 --- a/twilio/task_router/capability/capability_api.py +++ /dev/null @@ -1,68 +0,0 @@ -import time - -from .. import jwt - - -class CapabilityAPI(object): - """ - A token to control permissions for the TaskRouter service. - - :param str account_sid: The account to generate a token for - :param str auth_token: The auth token for the account. Used to sign the - token and will not be included in generated output. - :param str workspace_sid: The workspace to grant capabilities over - :param str worker_sid: The worker sid to grant capabilities over - :param str base_url: The base TaskRouter API URL - :param str base_ws_url: The base TaskRouter event stream URL - """ - def __init__(self, account_sid, auth_token, version, friendly_name): - self.account_sid = account_sid - self.auth_token = auth_token - - self.version = version - self.friendly_name = friendly_name; - self.policies = [] - - def add_policy(self, url, method, allowed, query_filter = None, post_filter = None): - policy = self.make_policy(url, method, allowed, query_filter, post_filter) - self.policies.append(policy) - - def allow(self, url, method, query_filter = None, post_filter = None): - self.add_policy(url, method, True, query_filter, post_filter) - - def deny(self, url, method, query_filter = None, post_filter = None): - self.add_policy(url, method, False, query_filter, post_filter) - - def generate_token(self, ttl = 3600, attributes = None): - return self._generate_token(ttl) - - def _generate_token(self, ttl, attributes=None): - payload = { - 'iss': self.account_sid, - 'exp': int(time.time()) + ttl, - 'version': self.version, - 'friendly_name': self.friendly_name, - 'policies': self.policies, - } - - if attributes is not None: - payload.update(attributes) - - return jwt.encode(payload, self.auth_token, 'HS256') - - def make_policy(self, url, method, allowed = True, query_filter = None, post_filter = None): - # Create a policy dictionary for the given resource and method. - - # :param str url: the resource URL to grant or deny access to - # :param str method: the HTTP method to allow or deny - # :param allowed bool: whether this request is allowed - # :param dict query_filter: specific GET parameter names to require or allow - # :param dict post_filter: POST parameter names to require or allow - - return { - 'url': url, - 'method': method, - 'allowed': allowed, - 'query_filter': query_filter or {}, - 'post_filter': post_filter or {} - } \ No newline at end of file diff --git a/twilio/task_router/capability/task_router_capability.py b/twilio/task_router/capability/task_router_capability.py deleted file mode 100644 index 6758020af6..0000000000 --- a/twilio/task_router/capability/task_router_capability.py +++ /dev/null @@ -1,187 +0,0 @@ -from .capability_api import CapabilityAPI - -import warnings -warnings.simplefilter('always', DeprecationWarning) - -TASK_ROUTER_BASE_URL = 'https://taskrouter.twilio.com' -TASK_ROUTER_BASE_EVENTS_URL = 'https://event-bridge.twilio.com/v1/wschannels' -TASK_ROUTER_VERSION = "v1" - -REQUIRED = {'required': True} -OPTIONAL = {'required': False} - -def deprecated(func): - def log_warning(*args, **kwargs): - # stacklevel = 2 makes the warning refer to the caller of the deprecation rather than the source of deprecation itself - warnings.warn("Call to deprecated function {}.".format(func.__name__), stacklevel = 2, category = DeprecationWarning) - return func(*args, **kwargs) - return log_warning - - -class TaskRouterCapability(CapabilityAPI): - def __init__(self, account_sid, auth_token, workspace_sid, channel_id): - super(TaskRouterCapability, self).__init__(account_sid, auth_token, TASK_ROUTER_VERSION, channel_id) - - self.workspace_sid = workspace_sid - self.channel_id = channel_id - self.base_url = TASK_ROUTER_BASE_URL + "/" + TASK_ROUTER_VERSION + "/Workspaces/" + workspace_sid - - # validate the JWT - self.validate_jwt() - - # set up resources - self.setup_resource() - - # add permissions to GET and POST to the event-bridge channel - self.allow_web_sockets(channel_id) - - # add permissions to fetch the instance resource - self.add_policy(self.resource_url, "GET", True) - - def setup_resource(self): - if self.channel_id[0:2] == "WS": - self.resource_url = self.base_url - elif self.channel_id[0:2] == "WK": - self.resource_url = self.base_url + "/Workers/" + self.channel_id - - activity_url = self.base_url + "/Activities" - self.allow(activity_url, "GET") - - reservations_url = self.base_url + "/Tasks/**" - self.allow(reservations_url, "GET") - - elif self.channel_id[0:2] == "WQ": - self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id - - def allow_web_sockets(self, channel_id): - web_socket_url = TASK_ROUTER_BASE_EVENTS_URL + "/" + self.account_sid + "/" + self.channel_id; - self.policies.append(self.make_policy(web_socket_url, "GET", True)) - self.policies.append(self.make_policy(web_socket_url, "POST", True)) - - def validate_jwt(self): - if self.account_sid is None or self.account_sid[0:2] != "AC": - raise ValueError('Invalid AccountSid provided: ' + self.account_sid) - if self.workspace_sid is None or self.workspace_sid[0:2] != "WS": - raise ValueError('Invalid WorkspaceSid provided: ' + self.workspace_sid) - if self.channel_id is None: - raise ValueError('ChannelId not provided') - - prefix = self.channel_id[0:2] - if prefix != "WS" and prefix != "WK" and prefix != "WQ": - raise ValueError('Invalid ChannelId provided: ' + self.channel_id) - - def allow_fetch_subresources(self): - self.allow(self.resource_url + "/**", "GET") - - def allow_updates(self): - self.allow(self.resource_url, "POST") - - def allow_updates_subresources(self): - self.allow(self.resource_url + "/**", "POST") - - def allow_delete(self): - self.allow(self.resource_url, "DELETE") - - def allow_delete_subresources(self): - self.allow(self.resource_url + "/**", "DELETE") - - @deprecated - def allow_worker_fetch_attributes(self): - if self.channel_id[0:2] == "WK": - self.policies.append(self.make_policy( - self.resource_url, - 'GET' - ) - ) - else: - raise ValueError("Deprecated function not applicable to non Worker") - - @deprecated - def allow_worker_activity_updates(self): - if self.channel_id[0:2] == "WK": - self.policies.append(self.make_policy( - self.resource_url, - 'POST', - True, - post_filter = {'ActivitySid': REQUIRED} - ) - ) - else: - raise ValueError("Deprecated function not applicable to non Worker") - - - @deprecated - def allow_task_reservation_updates(self): - if self.channel_id[0:2] == "WK": - tasks_url = self.base_url + "/Tasks/**" - self.policies.append(self.make_policy( - tasks_url, - 'POST', - True, - ) - ) - else: - raise ValueError("Deprecated function not applicable to non Worker") - - def get_resource_url(self): - return self.resource_url - - def generate_token(self, ttl = 3600): - task_router_attributes = {} - task_router_attributes["account_sid"] = self.account_sid - task_router_attributes["workspace_sid"] = self.workspace_sid - task_router_attributes["channel"] = self.channel_id - - if self.channel_id[0:2] == "WK": - task_router_attributes["worker_sid"] = self.channel_id - elif self.channel_id[0:2] == "WQ": - task_router_attributes["taskqueue_sid"] = self.channel_id - - return self._generate_token(ttl, task_router_attributes) - -class TaskRouterWorkerCapability(TaskRouterCapability): - def __init__(self, account_sid, auth_token, workspace_sid, worker_sid): - super(TaskRouterWorkerCapability, self).__init__(account_sid, auth_token, workspace_sid, worker_sid) - - self.reservations_url = self.base_url + "/Tasks/**" - self.activity_url = self.base_url + "/Activities" - - # add permissions to fetch the list of activities and list of worker reservations - self.allow(self.reservations_url, "GET") - self.allow(self.activity_url, "GET") - - def setup_resource(self): - self.resource_url = self.base_url + "/Workers/" + self.channel_id - - def allow_activity_updates(self): - self.policies.append(self.make_policy( - self.resource_url, - 'POST', - True, - post_filter = {'ActivitySid': REQUIRED} - ) - ) - def allow_reservation_updates(self): - self.policies.append(self.make_policy( - self.reservations_url, - 'POST', - True - ) - ) - -class TaskRouterTaskQueueCapability(TaskRouterCapability): - def __init__(self, account_sid, auth_token, workspace_sid, taskqueue_sid): - super(TaskRouterTaskQueueCapability, self).__init__(account_sid, auth_token, workspace_sid, taskqueue_sid) - - def setup_resource(self): - self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id - - -class TaskRouterWorkspaceCapability(TaskRouterCapability): - def __init__(self, account_sid, auth_token, workspace_sid): - super(TaskRouterWorkspaceCapability, self).__init__(account_sid, auth_token, workspace_sid, workspace_sid) - - def setup_resource(self): - self.resource_url = self.base_url - - From 15db38a83c78372eb8d1c32956d50cfb919363e9 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Tue, 28 Jul 2015 13:45:18 -0700 Subject: [PATCH 07/13] added helper function --- tests/task_router/test_capability.py | 18 +- .../test_task_router_capability.py | 164 +++++------------- 2 files changed, 46 insertions(+), 136 deletions(-) diff --git a/tests/task_router/test_capability.py b/tests/task_router/test_capability.py index 707fe97f83..eb4d15edba 100644 --- a/tests/task_router/test_capability.py +++ b/tests/task_router/test_capability.py @@ -55,21 +55,18 @@ def test_defaults(self): self.assertTrue(decoded is not None) websocket_url = ( - 'https://event-bridge.twilio.com/v1/wschannels/%s/%s' % - (self.account_sid, self.worker_sid) + 'https://event-bridge.twilio.com/v1/wschannels/{}/{}'.format(self.account_sid, self.worker_sid) ) expected = [ { - 'url': - 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities', + 'url': 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities', 'method': 'GET', 'allow': True, 'query_filter': {}, 'post_filter': {}, }, { - 'url': 'https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**' % - (self.workspace_sid), + 'url': 'https://taskrouter.twilio.com/v1/Workspaces/{}/Tasks/**'.format(self.workspace_sid), 'method': 'GET', 'allow': True, 'query_filter': {}, @@ -90,8 +87,7 @@ def test_defaults(self): 'post_filter': {}, }, { - 'url': 'https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s' % - (self.workspace_sid, self.worker_sid), + 'url': 'https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}'.format(self.workspace_sid, self.worker_sid), 'method': 'GET', 'allow': True, 'query_filter': {}, @@ -106,7 +102,7 @@ def test_allow_worker_activity_updates(self): decoded = jwt.decode(token, self.auth_token) self.assertTrue(decoded is not None) - url = 'https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s' % ( + url = 'https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}'.format( self.workspace_sid, self.worker_sid, ) @@ -126,7 +122,7 @@ def test_allow_worker_fetch_attributes(self): decoded = jwt.decode(token, self.auth_token) self.assertTrue(decoded is not None) - url = 'https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s' % ( + url = 'https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}'.format( self.workspace_sid, self.worker_sid, ) @@ -147,7 +143,7 @@ def test_allow_task_reservation_updates(self): decoded = jwt.decode(token, self.auth_token) self.assertTrue(decoded is not None) - url = 'https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**' % ( + url = 'https://taskrouter.twilio.com/v1/Workspaces/{}/Tasks/**'.format( self.workspace_sid, ) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 9cbe90c1aa..8c9cdb3131 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -1,3 +1,6 @@ +import sys +sys.path.append('/Users/wli/Projects/python-private/twilio/') + import unittest import warnings @@ -7,6 +10,14 @@ class TaskRouterCapabilityTest(unittest.TestCase): + def check_policy(self, method, url, policy): + print policy + self.assertEqual(url, policy['url']) + self.assertEqual(method, policy['method']) + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + def test_workspace_default(self): account_sid = "AC123" auth_token = "foobar" @@ -32,29 +43,12 @@ def test_workspace_default(self): policies = decoded['policies'] self.assertEqual(len(policies), 3) - # websocket GET - get_policy = policies[0] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allow']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) - - # websocket POST - post_policy = policies[1] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allow']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) - - # fetch GET - fetch_policy = policies[2] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allow']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + for method, url, policy in [ + ('GET', "https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", policies[0]), + ('POST', "https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", policies[1]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456", policies[2]), + ]: + yield self.check_policy, method, url, policy def test_worker_default(self): account_sid = "AC123" @@ -82,45 +76,14 @@ def test_worker_default(self): policies = decoded['policies'] self.assertEqual(len(policies), 5) - # activity GET - fetch_activity = policies[0] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) - self.assertEqual("GET", fetch_activity['method']) - self.assertTrue(fetch_activity['allow']) - self.assertEqual({}, fetch_activity['query_filter']) - self.assertEqual({}, fetch_activity['post_filter']) - - # reservation GET - fetch_reservation = policies[1] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) - self.assertEqual("GET", fetch_reservation['method']) - self.assertTrue(fetch_reservation['allow']) - self.assertEqual({}, fetch_reservation['query_filter']) - self.assertEqual({}, fetch_reservation['post_filter']) - - # websocket GET - get_policy = policies[2] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allow']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) - - # websocket POST - post_policy = policies[3] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allow']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) - - # fetch GET - fetch_policy = policies[4] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allow']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + for method, url, policy in [ + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", policies[0]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", policies[1]), + ('GET', "https://taskrouter.twilio.com/v1/wschannels/AC123/WK789", policies[2]), + ('POST', "https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", policies[3]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", policies[4]) + ]: + yield self.check_policy, method, url, policy def test_task_queue_default(self): account_sid = "AC123" @@ -148,29 +111,12 @@ def test_task_queue_default(self): policies = decoded['policies'] self.assertEqual(len(policies), 3) - # websocket GET - get_policy = policies[0] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allow']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) - - # websocket POST - post_policy = policies[1] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allow']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) - - # fetch GET - fetch_policy = policies[2] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allow']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + for method, url, policy in [ + ('GET', "https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", policies[0]), + ('POST', "https://event-bridge.twilio.com/v1/wschannels/AC123/WQ789", policies[1]) + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/TaskQueues/WQ789", policies[2]) + ]: + yield self.check_policy, method, url, policy def test_deprecated_worker(self): account_sid = "AC123" @@ -199,46 +145,14 @@ def test_deprecated_worker(self): self.assertEqual(len(policies), 5) # should expect 5 policies - - # activity GET - fetch_activity = policies[0] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", fetch_activity['url']) - self.assertEqual("GET", fetch_activity['method']) - self.assertTrue(fetch_activity['allow']) - self.assertEqual({}, fetch_activity['query_filter']) - self.assertEqual({}, fetch_activity['post_filter']) - - # reservation GET - fetch_reservation = policies[1] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", fetch_reservation['url']) - self.assertEqual("GET", fetch_reservation['method']) - self.assertTrue(fetch_reservation['allow']) - self.assertEqual({}, fetch_reservation['query_filter']) - self.assertEqual({}, fetch_reservation['post_filter']) - - # websocket GET - get_policy = policies[2] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allow']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) - - # websocket POST - post_policy = policies[3] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allow']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) - - # fetch GET - fetch_policy = policies[4] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allow']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + for method, url, policy in [ + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", policies[0]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", policies[1]), + ('GET', "https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", policies[2]), + ('POST', "https://event-bridge.twilio.com/v1/wschannels/AC123/WK789", policies[3]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", policies[4]) + ]: + yield self.check_policy, method, url, policy # check deprecated warnings with warnings.catch_warnings(record=True) as w: From 3aaae2451de6244158479faabdbb0b56b46b2d52 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Tue, 28 Jul 2015 15:48:22 -0700 Subject: [PATCH 08/13] added helper function, formatting --- .../test_task_router_capability.py | 48 ++++------ .../test_task_router_worker_capability.py | 96 +++++++------------ .../test_task_router_workspace_capability.py | 73 +++++++------- twilio/task_router/__init__.py | 58 +++++------ 4 files changed, 118 insertions(+), 157 deletions(-) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 8c9cdb3131..7d1a99c644 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -1,5 +1,6 @@ import sys -sys.path.append('/Users/wli/Projects/python-private/twilio/') +sys.path.append('../../') +sys.path.append('/Library/Python/2.7/site-packages') import unittest import warnings @@ -11,13 +12,25 @@ class TaskRouterCapabilityTest(unittest.TestCase): def check_policy(self, method, url, policy): - print policy self.assertEqual(url, policy['url']) self.assertEqual(method, policy['method']) self.assertTrue(policy['allow']) self.assertEqual({}, policy['query_filter']) self.assertEqual({}, policy['post_filter']) + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["channel"], channel_id) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], channel_id) + + if 'worker_sid' in decoded.keys(): + self.assertEqual(decoded['worker_sid'], channel_sid) + if 'taskqueue_sid' in decoded.keys(): + self.assertEqual(decoded['taskqueue_sid'], channel_sid) + def test_workspace_default(self): account_sid = "AC123" auth_token = "foobar" @@ -33,12 +46,7 @@ def test_workspace_default(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], account_sid) - self.assertEqual(decoded["account_sid"], account_sid) - self.assertEqual(decoded["workspace_sid"], workspace_sid) - self.assertEqual(decoded["channel"], channel_id) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], channel_id) + self.check_decoded(decoded, account_sid, workspace_sid, channel_id) policies = decoded['policies'] self.assertEqual(len(policies), 3) @@ -65,13 +73,7 @@ def test_worker_default(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], account_sid) - self.assertEqual(decoded["account_sid"], account_sid) - self.assertEqual(decoded["workspace_sid"], workspace_sid) - self.assertEqual(decoded["worker_sid"], worker_sid) - self.assertEqual(decoded["channel"], worker_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], worker_sid) + self.check_decoded(decoded, account_sid, workspace_sid, channel_id, worker_sid) policies = decoded['policies'] self.assertEqual(len(policies), 5) @@ -100,13 +102,7 @@ def test_task_queue_default(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], account_sid) - self.assertEqual(decoded["account_sid"], account_sid) - self.assertEqual(decoded["workspace_sid"], workspace_sid) - self.assertEqual(decoded["taskqueue_sid"], taskqueue_sid) - self.assertEqual(decoded["channel"], taskqueue_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], taskqueue_sid) + self.check_decoded(decoded, account_sid, workspace_sid, channel_id, taskqueue_sid) policies = decoded['policies'] self.assertEqual(len(policies), 3) @@ -133,13 +129,7 @@ def test_deprecated_worker(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], account_sid) - self.assertEqual(decoded["account_sid"], account_sid) - self.assertEqual(decoded["workspace_sid"], workspace_sid) - self.assertEqual(decoded["worker_sid"], worker_sid) - self.assertEqual(decoded["channel"], worker_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], worker_sid) + self.check_decoded(decoded, account_sid, workspace_sid, channel_id, worker_sid) policies = decoded['policies'] self.assertEqual(len(policies), 5) diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index 35abb5b831..e2ca7a2cd9 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -1,3 +1,7 @@ +import sys +sys.path.append('../../') +sys.path.append('/Library/Python/2.7/site-packages') + import time import unittest @@ -6,6 +10,25 @@ class TaskRouterWorkerCapabilityTest(unittest.TestCase): + def check_policy(self, method, url, policy): + self.assertEqual(url, policy['url']) + self.assertEqual(method, policy['method']) + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["channel"], channel_id) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], channel_id) + + if 'worker_sid' in decoded.keys(): + self.assertEqual(decoded['worker_sid'], channel_sid) + if 'taskqueue_sid' in decoded.keys(): + self.assertEqual(decoded['taskqueue_sid'], channel_sid) def setUp(self): self.account_sid = "AC123" @@ -22,13 +45,7 @@ def test_generate_token(self): decoded = jwt.decode(token, self.auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], self.account_sid) - self.assertEqual(decoded["account_sid"], self.account_sid) - self.assertEqual(decoded["workspace_sid"], self.workspace_sid) - self.assertEqual(decoded["worker_sid"], self.worker_sid) - self.assertEqual(decoded["channel"], self.worker_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], self.worker_sid) + self.check_decoded(decoded, self.account_sid, self.workspace_sid, self.worker_sid, self.worker_sid) def test_generate_token_with_default_ttl(self): token = self.capability.generate_token() @@ -57,56 +74,21 @@ def test_defaults(self): decoded = jwt.decode(token, self.auth_token) self.assertIsNotNone(decoded) - websocket_url = 'https://event-bridge.twilio.com/v1/wschannels/%s/%s' % (self.account_sid, self.worker_sid) + websocket_url = 'https://event-bridge.twilio.com/v1/wschannels/{}/{}'.format(self.account_sid, self.worker_sid) # expect 5 policies policies = decoded['policies'] self.assertEqual(len(policies), 5) - # policy 0 - GET websocket - get_policy = policies[0] - self.assertIsNotNone(get_policy) - self.assertEqual(get_policy['url'], websocket_url) - self.assertEqual(get_policy['method'], 'GET') - self.assertTrue(get_policy['allow']) - self.assertEqual(get_policy['query_filter'], {}) - self.assertEqual(get_policy['post_filter'], {}) - - # policy 1 - POST - post_policy = policies[1] - self.assertIsNotNone(post_policy) - self.assertEqual(post_policy['url'], websocket_url) - self.assertEqual(post_policy['method'], 'POST') - self.assertTrue(post_policy['allow']) - self.assertEqual(post_policy['query_filter'], {}) - self.assertEqual(post_policy['post_filter'], {}) - - # policy 2 - Worker fetch - worker_fetch_policy = policies[2] - self.assertIsNotNone(worker_fetch_policy) - self.assertEqual(worker_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789') - self.assertEqual(worker_fetch_policy['method'], 'GET') - self.assertTrue(worker_fetch_policy['allow']) - self.assertEqual(worker_fetch_policy['query_filter'], {}) - self.assertEqual(worker_fetch_policy['post_filter'], {}) - - # policy 3 - Reservation fetch - reservation_fetch_policy = policies[3] - self.assertIsNotNone(reservation_fetch_policy) - self.assertEqual(reservation_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**') - self.assertEqual(reservation_fetch_policy['method'], 'GET') - self.assertTrue(reservation_fetch_policy['allow']) - self.assertEqual(reservation_fetch_policy['query_filter'], {}) - self.assertEqual(reservation_fetch_policy['post_filter'], {}) - - # policy 4 - Activity fetch - activity_fetch_policy = policies[4] - self.assertIsNotNone(activity_fetch_policy) - self.assertEqual(activity_fetch_policy['url'], 'https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities') - self.assertEqual(activity_fetch_policy['method'], 'GET') - self.assertTrue(activity_fetch_policy['allow']) - self.assertEqual(activity_fetch_policy['query_filter'], {}) - self.assertEqual(activity_fetch_policy['post_filter'], {}) + # should expect 5 policies + for method, url, policy in [ + ('GET', websocket_url, policies[0]), + ('POST', websocket_url, policies[1]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Workers/WK789", policies[2]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Tasks/**", policies[3]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/Activities", policies[4]) + ]: + yield self.check_policy, method, url, policy def test_allow_activity_updates(self): @@ -123,7 +105,7 @@ def test_allow_activity_updates(self): self.assertEqual(len(policies), 6) policy = policies[5] - url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Workers/%s" % (self.workspace_sid, self.worker_sid) + url = "https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}".format(self.workspace_sid, self.worker_sid) self.assertEqual(url, policy["url"]) self.assertEqual("POST", policy["method"]) @@ -147,13 +129,9 @@ def test_allow_reservation_updates(self): policy = policies[5] - url = "https://taskrouter.twilio.com/v1/Workspaces/%s/Tasks/**" % self.workspace_sid + url = "https://taskrouter.twilio.com/v1/Workspaces/{}/Tasks/**".format(self.workspace_sid) - self.assertEqual(url, policy["url"]) - self.assertEqual("POST", policy["method"]) - self.assertTrue(policy["allow"]) - self.assertEqual({}, policy["query_filter"]) - self.assertEqual({}, policy['post_filter']) + self.check_policy('POST', url, policy) if __name__ == "__main__": unittest.main() diff --git a/tests/task_router/test_task_router_workspace_capability.py b/tests/task_router/test_task_router_workspace_capability.py index b35e692897..87287dd103 100644 --- a/tests/task_router/test_task_router_workspace_capability.py +++ b/tests/task_router/test_task_router_workspace_capability.py @@ -1,3 +1,7 @@ +import sys +sys.path.append('../../') +sys.path.append('/Library/Python/2.7/site-packages') + import time import unittest @@ -6,6 +10,25 @@ class TaskRouterWorkspaceCapabilityTest(unittest.TestCase): + def check_policy(self, method, url, policy): + self.assertEqual(url, policy['url']) + self.assertEqual(method, policy['method']) + self.assertTrue(policy['allow']) + self.assertEqual({}, policy['query_filter']) + self.assertEqual({}, policy['post_filter']) + + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + self.assertEqual(decoded["iss"], account_sid) + self.assertEqual(decoded["account_sid"], account_sid) + self.assertEqual(decoded["workspace_sid"], workspace_sid) + self.assertEqual(decoded["channel"], channel_id) + self.assertEqual(decoded["version"], "v1") + self.assertEqual(decoded["friendly_name"], channel_id) + + if 'worker_sid' in decoded.keys(): + self.assertEqual(decoded['worker_sid'], channel_sid) + if 'taskqueue_sid' in decoded.keys(): + self.assertEqual(decoded['taskqueue_sid'], channel_sid) def setUp(self): self.account_sid = "AC123" @@ -21,12 +44,7 @@ def test_generate_token(self): decoded = jwt.decode(token, self.auth_token) self.assertIsNotNone(decoded) - self.assertEqual(decoded["iss"], self.account_sid) - self.assertEqual(decoded["account_sid"], self.account_sid) - self.assertEqual(decoded["workspace_sid"], self.workspace_sid) - self.assertEqual(decoded["channel"], self.workspace_sid) - self.assertEqual(decoded["version"], "v1") - self.assertEqual(decoded["friendly_name"], self.workspace_sid) + self.check_decoded(decoded, self.account_sid, self.workspace_sid, self.workspace_sid) def test_generate_token_with_default_ttl(self): token = self.capability.generate_token() @@ -58,29 +76,12 @@ def test_default(self): policies = decoded['policies'] self.assertEqual(len(policies), 3) - # websocket GET - get_policy = policies[0] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", get_policy['url']) - self.assertEqual("GET", get_policy['method']) - self.assertTrue(get_policy['allow']) - self.assertEqual({}, get_policy['query_filter']) - self.assertEqual({}, get_policy['post_filter']) - - # websocket POST - post_policy = policies[1] - self.assertEqual("https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", post_policy['url']) - self.assertEqual("POST", post_policy['method']) - self.assertTrue(post_policy['allow']) - self.assertEqual({}, post_policy['query_filter']) - self.assertEqual({}, post_policy['post_filter']) - - # fetch GET - fetch_policy = policies[2] - self.assertEqual("https://taskrouter.twilio.com/v1/Workspaces/WS456", fetch_policy['url']) - self.assertEqual("GET", fetch_policy['method']) - self.assertTrue(fetch_policy['allow']) - self.assertEqual({}, fetch_policy['query_filter']) - self.assertEqual({}, fetch_policy['post_filter']) + for method, url, policy in [ + ('GET', "https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", policies[0]), + ('POST', "https://event-bridge.twilio.com/v1/wschannels/AC123/WS456", policies[1]), + ('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456", policies[2]) + ]: + yield self.check_policy, method, url, policy def test_allow_fetch_subresources(self): self.capability.allow_fetch_subresources() @@ -95,14 +96,9 @@ def test_allow_fetch_subresources(self): self.assertEqual(len(policies), 4) # confirm the additional policy generated with allow_fetch_subresources() - policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") - self.assertEqual(policy['method'], "GET") - self.assertTrue(policy['allow']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.check_policy('GET', "https://taskrouter.twilio.com/v1/Workspaces/WS456/**", policy) def test_allow_updates_subresources(self): self.capability.allow_updates_subresources() @@ -117,14 +113,9 @@ def test_allow_updates_subresources(self): self.assertEqual(len(policies), 4) # confirm the additional policy generated with allow_updates_subresources() - policy = policies[3] - self.assertEqual(policy['url'], "https://taskrouter.twilio.com/v1/Workspaces/WS456/**") - self.assertEqual(policy['method'], "POST") - self.assertTrue(policy['allow']) - self.assertEqual({}, policy['query_filter']) - self.assertEqual({}, policy['post_filter']) + self.check_policy('POST', "https://taskrouter.twilio.com/v1/Workspaces/WS456/**", policy) if __name__ == "__main__": unittest.main() diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py index 58a313d5e2..065816c124 100644 --- a/twilio/task_router/__init__.py +++ b/twilio/task_router/__init__.py @@ -11,7 +11,6 @@ REQUIRED = {'required': True} OPTIONAL = {'required': False} - def deprecated(func): def log_warning(*args, **kwargs): # stacklevel = 2 makes the warning refer to the caller of the @@ -32,9 +31,7 @@ def __init__(self, account_sid, auth_token, workspace_sid, channel_id): self.workspace_sid = workspace_sid self.channel_id = channel_id - self.base_url = (TASK_ROUTER_BASE_URL + "/" + - TASK_ROUTER_VERSION + - "/Workspaces/" + workspace_sid) + self.base_url = "{}/{}/Workspaces/{}".format(TASK_ROUTER_BASE_URL, TASK_ROUTER_VERSION, workspace_sid) # validate the JWT self.validate_jwt() @@ -48,10 +45,14 @@ def __init__(self, account_sid, auth_token, workspace_sid, channel_id): # add permissions to fetch the instance resource self.add_policy(self.resource_url, "GET", True) + @property + def channel_prefix(self): + return self.channel_id[0:2] + def setup_resource(self): - if self.channel_id[0:2] == "WS": + if self.channel_prefix == "WS": self.resource_url = self.base_url - elif self.channel_id[0:2] == "WK": + elif self.channel_prefix == "WK": self.resource_url = self.base_url + "/Workers/" + self.channel_id activity_url = self.base_url + "/Activities" @@ -60,7 +61,7 @@ def setup_resource(self): reservations_url = self.base_url + "/Tasks/**" self.allow(reservations_url, "GET") - elif self.channel_id[0:2] == "WQ": + elif self.channel_prefix == "WQ": self.resource_url = self.base_url + \ "/TaskQueues/" + self.channel_id @@ -81,8 +82,7 @@ def validate_jwt(self): if self.channel_id is None: raise ValueError('ChannelId not provided') - prefix = self.channel_id[0:2] - if prefix != "WS" and prefix != "WK" and prefix != "WQ": + if self.channel_prefix != "WS" and self.channel_prefix != "WK" and self.channel_prefix != "WQ": raise ValueError('Invalid ChannelId provided: ' + self.channel_id) def allow_fetch_subresources(self): @@ -102,16 +102,16 @@ def allow_delete_subresources(self): @deprecated def allow_worker_fetch_attributes(self): - if self.channel_id[0:2] == "WK": + if self.channel_prefix != "WK": + raise ValueError("Deprecated func not applicable to non Worker") + else: self.policies.append(self.make_policy( self.resource_url, 'GET')) - else: - raise ValueError("Deprecated func not applicable to non Worker") @deprecated def allow_worker_activity_updates(self): - if self.channel_id[0:2] == "WK": + if self.channel_prefix == "WK": self.policies.append(self.make_policy( self.resource_url, 'POST', @@ -122,7 +122,7 @@ def allow_worker_activity_updates(self): @deprecated def allow_task_reservation_updates(self): - if self.channel_id[0:2] == "WK": + if self.channel_prefix == "WK": tasks_url = self.base_url + "/Tasks/**" self.policies.append(self.make_policy( tasks_url, @@ -147,14 +147,15 @@ def deny(self, url, method, query_filter=None, post_filter=None): def make_policy(self, url, method, allowed=True, query_filter=None, post_filter=None): - # Create a policy dictionary for the given resource and method. - # :param str url: the resource URL to grant or deny access to - # :param str method: the HTTP method to allow or deny - # :param allowed bool: whether this request is allowed - # :param dict query_filter: specific GET parameter names - # to require or allow - # :param dict post_filter: POST parameter names - # to require or allow + """Create a policy dictionary for the given resource and method. + :param str url: the resource URL to grant or deny access to + :param str method: the HTTP method to allow or deny + :param allowed bool: whether this request is allowed + :param dict query_filter: specific GET parameter names + to require or allow + :param dict post_filter: POST parameter names + to require or allow + """ return { 'url': url, @@ -168,14 +169,15 @@ def get_resource_url(self): return self.resource_url def generate_token(self, ttl=3600): - task_router_attributes = {} - task_router_attributes["account_sid"] = self.account_sid - task_router_attributes["workspace_sid"] = self.workspace_sid - task_router_attributes["channel"] = self.channel_id + task_router_attributes = { + 'account_sid': self.account_sid, + 'workspace_sid': self.workspace_sid, + 'channel': self.channel_id + } - if self.channel_id[0:2] == "WK": + if self.channel_prefix == "WK": task_router_attributes["worker_sid"] = self.channel_id - elif self.channel_id[0:2] == "WQ": + elif self.channel_prefix == "WQ": task_router_attributes["taskqueue_sid"] = self.channel_id return self._generate_token(ttl, task_router_attributes) From 0255c472182e7c01d732e6e24c14c2f80f6d4682 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Tue, 28 Jul 2015 16:00:24 -0700 Subject: [PATCH 09/13] forgot to remove sys path --- tests/task_router/test_task_router_capability.py | 4 ---- tests/task_router/test_task_router_worker_capability.py | 4 ---- tests/task_router/test_task_router_workspace_capability.py | 4 ---- 3 files changed, 12 deletions(-) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 7d1a99c644..3f3f4f0fb5 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -1,7 +1,3 @@ -import sys -sys.path.append('../../') -sys.path.append('/Library/Python/2.7/site-packages') - import unittest import warnings diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index e2ca7a2cd9..6fad95e558 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -1,7 +1,3 @@ -import sys -sys.path.append('../../') -sys.path.append('/Library/Python/2.7/site-packages') - import time import unittest diff --git a/tests/task_router/test_task_router_workspace_capability.py b/tests/task_router/test_task_router_workspace_capability.py index 87287dd103..3f4f644389 100644 --- a/tests/task_router/test_task_router_workspace_capability.py +++ b/tests/task_router/test_task_router_workspace_capability.py @@ -1,7 +1,3 @@ -import sys -sys.path.append('../../') -sys.path.append('/Library/Python/2.7/site-packages') - import time import unittest From c58cb4ae201f2a0c6b14928b4aa0422a16f42514 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Tue, 28 Jul 2015 16:02:25 -0700 Subject: [PATCH 10/13] removed trailing whitespaces --- tests/task_router/test_task_router_capability.py | 4 ++-- tests/task_router/test_task_router_worker_capability.py | 4 ++-- tests/task_router/test_task_router_workspace_capability.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 3f3f4f0fb5..0fa6c45805 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -14,7 +14,7 @@ def check_policy(self, method, url, policy): self.assertEqual({}, policy['query_filter']) self.assertEqual({}, policy['post_filter']) - def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): self.assertEqual(decoded["iss"], account_sid) self.assertEqual(decoded["account_sid"], account_sid) self.assertEqual(decoded["workspace_sid"], workspace_sid) @@ -22,7 +22,7 @@ def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel self.assertEqual(decoded["version"], "v1") self.assertEqual(decoded["friendly_name"], channel_id) - if 'worker_sid' in decoded.keys(): + if 'worker_sid' in decoded.keys(): self.assertEqual(decoded['worker_sid'], channel_sid) if 'taskqueue_sid' in decoded.keys(): self.assertEqual(decoded['taskqueue_sid'], channel_sid) diff --git a/tests/task_router/test_task_router_worker_capability.py b/tests/task_router/test_task_router_worker_capability.py index 6fad95e558..4f7578d91b 100644 --- a/tests/task_router/test_task_router_worker_capability.py +++ b/tests/task_router/test_task_router_worker_capability.py @@ -13,7 +13,7 @@ def check_policy(self, method, url, policy): self.assertEqual({}, policy['query_filter']) self.assertEqual({}, policy['post_filter']) - def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): self.assertEqual(decoded["iss"], account_sid) self.assertEqual(decoded["account_sid"], account_sid) self.assertEqual(decoded["workspace_sid"], workspace_sid) @@ -21,7 +21,7 @@ def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel self.assertEqual(decoded["version"], "v1") self.assertEqual(decoded["friendly_name"], channel_id) - if 'worker_sid' in decoded.keys(): + if 'worker_sid' in decoded.keys(): self.assertEqual(decoded['worker_sid'], channel_sid) if 'taskqueue_sid' in decoded.keys(): self.assertEqual(decoded['taskqueue_sid'], channel_sid) diff --git a/tests/task_router/test_task_router_workspace_capability.py b/tests/task_router/test_task_router_workspace_capability.py index 3f4f644389..2767afd59d 100644 --- a/tests/task_router/test_task_router_workspace_capability.py +++ b/tests/task_router/test_task_router_workspace_capability.py @@ -13,7 +13,7 @@ def check_policy(self, method, url, policy): self.assertEqual({}, policy['query_filter']) self.assertEqual({}, policy['post_filter']) - def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): + def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel_sid=None): self.assertEqual(decoded["iss"], account_sid) self.assertEqual(decoded["account_sid"], account_sid) self.assertEqual(decoded["workspace_sid"], workspace_sid) @@ -21,7 +21,7 @@ def check_decoded(self, decoded, account_sid, workspace_sid, channel_id, channel self.assertEqual(decoded["version"], "v1") self.assertEqual(decoded["friendly_name"], channel_id) - if 'worker_sid' in decoded.keys(): + if 'worker_sid' in decoded.keys(): self.assertEqual(decoded['worker_sid'], channel_sid) if 'taskqueue_sid' in decoded.keys(): self.assertEqual(decoded['taskqueue_sid'], channel_sid) From ef8d9b9621262cb9212d10c6dfa92ba7d55746fc Mon Sep 17 00:00:00 2001 From: Jen Li Date: Tue, 28 Jul 2015 16:23:37 -0700 Subject: [PATCH 11/13] removed unnecessary constructors and added .format() --- twilio/task_router/__init__.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py index 065816c124..4224884117 100644 --- a/twilio/task_router/__init__.py +++ b/twilio/task_router/__init__.py @@ -62,12 +62,10 @@ def setup_resource(self): self.allow(reservations_url, "GET") elif self.channel_prefix == "WQ": - self.resource_url = self.base_url + \ - "/TaskQueues/" + self.channel_id + self.resource_url = "{}/TaskQueues/{}".format(self.base_url, self.channel_id) def allow_web_sockets(self, channel_id): - web_socket_url = TASK_ROUTER_BASE_EVENTS_URL + "/" + \ - self.account_sid + "/" + self.channel_id + web_socket_url = "{}/{}/{}".format(TASK_ROUTER_BASE_EVENTS_URL, self.account_sid, self.channel_id) self.policies.append(self.make_policy(web_socket_url, "GET", True)) self.policies.append(self.make_policy(web_socket_url, "POST", True)) @@ -230,22 +228,10 @@ def allow_reservation_updates(self): class TaskRouterTaskQueueCapability(TaskRouterCapability): - def __init__(self, account_sid, auth_token, workspace_sid, taskqueue_sid): - super(TaskRouterTaskQueueCapability, self).__init__(account_sid, - auth_token, - workspace_sid, - taskqueue_sid) - def setup_resource(self): self.resource_url = self.base_url + "/TaskQueues/" + self.channel_id class TaskRouterWorkspaceCapability(TaskRouterCapability): - def __init__(self, account_sid, auth_token, workspace_sid): - super(TaskRouterWorkspaceCapability, self).__init__(account_sid, - auth_token, - workspace_sid, - workspace_sid) - def setup_resource(self): self.resource_url = self.base_url From 7435b95610eda19b0205c01ca1f1830611f3c268 Mon Sep 17 00:00:00 2001 From: Jen Li Date: Wed, 29 Jul 2015 17:53:02 -0700 Subject: [PATCH 12/13] added back constructor for TaskRouterWorkspaceCapability and fixed 80 chars --- .../test_task_router_capability.py | 6 +++--- twilio/task_router/__init__.py | 20 +++++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/task_router/test_task_router_capability.py b/tests/task_router/test_task_router_capability.py index 0fa6c45805..a32768bfbf 100644 --- a/tests/task_router/test_task_router_capability.py +++ b/tests/task_router/test_task_router_capability.py @@ -69,7 +69,7 @@ def test_worker_default(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.check_decoded(decoded, account_sid, workspace_sid, channel_id, worker_sid) + self.check_decoded(decoded, account_sid, workspace_sid, worker_sid, worker_sid) policies = decoded['policies'] self.assertEqual(len(policies), 5) @@ -98,7 +98,7 @@ def test_task_queue_default(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.check_decoded(decoded, account_sid, workspace_sid, channel_id, taskqueue_sid) + self.check_decoded(decoded, account_sid, workspace_sid, taskqueue_sid, taskqueue_sid) policies = decoded['policies'] self.assertEqual(len(policies), 3) @@ -125,7 +125,7 @@ def test_deprecated_worker(self): decoded = jwt.decode(token, auth_token) self.assertIsNotNone(decoded) - self.check_decoded(decoded, account_sid, workspace_sid, channel_id, worker_sid) + self.check_decoded(decoded, account_sid, workspace_sid, worker_sid, worker_sid) policies = decoded['policies'] self.assertEqual(len(policies), 5) diff --git a/twilio/task_router/__init__.py b/twilio/task_router/__init__.py index 4224884117..91dca999a6 100644 --- a/twilio/task_router/__init__.py +++ b/twilio/task_router/__init__.py @@ -11,6 +11,7 @@ REQUIRED = {'required': True} OPTIONAL = {'required': False} + def deprecated(func): def log_warning(*args, **kwargs): # stacklevel = 2 makes the warning refer to the caller of the @@ -31,7 +32,9 @@ def __init__(self, account_sid, auth_token, workspace_sid, channel_id): self.workspace_sid = workspace_sid self.channel_id = channel_id - self.base_url = "{}/{}/Workspaces/{}".format(TASK_ROUTER_BASE_URL, TASK_ROUTER_VERSION, workspace_sid) + self.base_url = "{}/{}/Workspaces/{}".format(TASK_ROUTER_BASE_URL, + TASK_ROUTER_VERSION, + workspace_sid) # validate the JWT self.validate_jwt() @@ -62,10 +65,12 @@ def setup_resource(self): self.allow(reservations_url, "GET") elif self.channel_prefix == "WQ": - self.resource_url = "{}/TaskQueues/{}".format(self.base_url, self.channel_id) + self.resource_url = "{}/TaskQueues/{}".format( + self.base_url, self.channel_id) def allow_web_sockets(self, channel_id): - web_socket_url = "{}/{}/{}".format(TASK_ROUTER_BASE_EVENTS_URL, self.account_sid, self.channel_id) + web_socket_url = "{}/{}/{}".format(TASK_ROUTER_BASE_EVENTS_URL, + self.account_sid, self.channel_id) self.policies.append(self.make_policy(web_socket_url, "GET", True)) self.policies.append(self.make_policy(web_socket_url, "POST", True)) @@ -80,7 +85,8 @@ def validate_jwt(self): if self.channel_id is None: raise ValueError('ChannelId not provided') - if self.channel_prefix != "WS" and self.channel_prefix != "WK" and self.channel_prefix != "WQ": + if self.channel_prefix != "WS" and self.channel_prefix != "WK" \ + and self.channel_prefix != "WQ": raise ValueError('Invalid ChannelId provided: ' + self.channel_id) def allow_fetch_subresources(self): @@ -233,5 +239,11 @@ def setup_resource(self): class TaskRouterWorkspaceCapability(TaskRouterCapability): + def __init__(self, account_sid, auth_token, workspace_sid): + super(TaskRouterWorkspaceCapability, self).__init__(account_sid, + auth_token, + workspace_sid, + workspace_sid) + def setup_resource(self): self.resource_url = self.base_url From 2b691507d0d631fa3ad1416625a03a81ccac3567 Mon Sep 17 00:00:00 2001 From: matt Date: Tue, 11 Aug 2015 10:14:10 -0700 Subject: [PATCH 13/13] Bumping version to 4.5.0 --- CHANGES.md | 10 ++++++++++ twilio/version.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 11b8e7dd71..edb4ea582a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,16 @@ twilio-python Changelog Here you can see the full list of changes between each twilio-python release. +Version 4.5.0 +------------- + +Released August 11, 2015: + +- Add support for new Taskrouter JWT Functionality, JWTs now grant access to + - Workspace + - Worker + - TaskQueue + Version 4.4.0 ------------- diff --git a/twilio/version.py b/twilio/version.py index 953ebe5125..a14cd79c93 100644 --- a/twilio/version.py +++ b/twilio/version.py @@ -1,2 +1,2 @@ -__version_info__ = ('4', '4', '0') +__version_info__ = ('4', '5', '0') __version__ = '.'.join(__version_info__)