From 639b8a692dbe9a1a9eca35e84569c34e4e766a38 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Mon, 7 Oct 2019 17:07:09 +0200 Subject: [PATCH 01/24] Read voice webhook by id --- messagebird/client.py | 6 +++ messagebird/voice_webhook.py | 80 ++++++++++++++++++++++++++++++++++++ tests/test_voice_webhook.py | 41 ++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 messagebird/voice_webhook.py create mode 100644 tests/test_voice_webhook.py diff --git a/messagebird/client.py b/messagebird/client.py index 45a5464..a41e4bd 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -12,6 +12,7 @@ from messagebird.hlr import HLR from messagebird.message import Message, MessageList from messagebird.mms import MMS +from messagebird.voice_webhook import VoiceWebhook from messagebird.voicemessage import VoiceMessage from messagebird.lookup import Lookup from messagebird.verify import Verify @@ -46,6 +47,7 @@ VOICE_LEGS_PATH = 'legs' VOICE_RECORDINGS_PATH = 'recordings' VOICE_TRANSCRIPTIONS_PATH = 'transcriptions' +VOICE_WEB_HOOKS_PATH = 'webhooks' class ErrorException(Exception): @@ -423,6 +425,10 @@ def voice_recording_download(self, call_id, leg_id, recording_id): recording_file = self.request_store_as_file(VOICE_API_ROOT + recording_file, recording_id + '.wav') return VOICE_API_ROOT + recording_file + def voice_read_webhook(self, id): + uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + str(id) + return VoiceWebhook().load(self.request(uri, 'GET', None, VOICE_TYPE)) + def call_flow(self, id): return CallFlow().load(self.request('call-flows/' + str(id), 'GET', None, VOICE_TYPE)) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py new file mode 100644 index 0000000..3876b69 --- /dev/null +++ b/messagebird/voice_webhook.py @@ -0,0 +1,80 @@ +from messagebird.base import Base + + +class VoiceWebhook(Base): + + def __init__(self): + self.id = None + self.url = None + self.token = None + self._createdDatetime = None + self._updatedDatetime = None + self._links = None + + @property + def createdDatetime(self): + return self._createdDatetime + + @createdDatetime.setter + def createdAt(self, value): + if value is not None: + self._createdDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') + + @property + def updatedDatetime(self): + return self._updatedDatetime + + @updatedDatetime.setter + def updatedAt(self, value): + if value is not None: + self._updatedDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') + + def load(self, data): + if data.get('data') is not None: + items = data.get('data')[0].items() + else: + items = list(data.items()) + + for name, value in items: + if hasattr(self, name) and not callable(getattr(self, name)): + setattr(self, name, value) + + return self + + def __str__(self): + return "\n".join([ + 'webhook id : %s' % self.id, + 'url : %s' % self.url, + 'token : %s' % self.token, + 'created date time : %s' % self._createdDatetime, + 'updated date time : %s' % self._updatedDatetime, + 'links : %s' % self._links + ]) + + +class VoiceWebhookList(Base): + + def __init__(self): + self._items = None + + @property + def data(self): + return self._items + + @data.setter + def data(self, value): + if isinstance(value, list): + self._items = [] + for item in value: + self._items.append(VoiceWebhook().load(item)) + + def __str__(self): + item_ids = [] + if self._items is not None: + for voice_item in self._items: + item_ids.append(voice_item.id) + + return "\n".join([ + 'items IDs : %s' % item_ids, + 'count : %s' % len(item_ids) + ]) diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py new file mode 100644 index 0000000..c01e979 --- /dev/null +++ b/tests/test_voice_webhook.py @@ -0,0 +1,41 @@ +import unittest + +from messagebird import Client +from messagebird.client import VOICE_WEB_HOOKS_PATH, VOICE_API_ROOT + +try: + from unittest.mock import Mock +except ImportError: + # mock was added to unittest in Python 3.3, but was an external library + # before. + from mock import Mock + + +class TestVoiceWebhook(unittest.TestCase): + + def test_voice_webhook_read(self): + http_client = Mock() + http_client.request.return_value = '''{ + "data": [ + { + "id": "534e1848-235f-482d-983d-e3e11a04f58a", + "url": "https://example.com/", + "token": "foobar", + "createdAt": "2017-03-15T13:28:32Z", + "updatedAt": "2017-03-15T13:28:32Z" + } + ], + "_links": { + "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" + } + }''' + webhook_id = '534e1848-235f-482d-983d-e3e11a04f58a' + webhook_token = 'foobar' + + voice_webhook = Client('', http_client).voice_read_webhook(webhook_id) + + http_client.request.assert_called_once_with( + VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'GET', None) + + self.assertEqual(webhook_id, voice_webhook.id) + self.assertEqual(webhook_token, voice_webhook.token) From 781bc7970bd26b9820152f5fd68173ebff9b5887 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 11:22:21 +0200 Subject: [PATCH 02/24] Add class CreateWebhookRequest * Validation * Tests * ValidationError --- messagebird/error.py | 29 ++++++++--- messagebird/validation.py | 6 +++ messagebird/voice_webhook.py | 37 ++++++++++++++ tests/test_voice_webhook.py | 95 +++++++++++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 messagebird/validation.py diff --git a/messagebird/error.py b/messagebird/error.py index 7084735..46abe18 100644 --- a/messagebird/error.py +++ b/messagebird/error.py @@ -1,10 +1,27 @@ from messagebird.base import Base + class Error(Base): - def __init__(self): - self.code = None - self.description = None - self.parameter = None + def __init__(self): + self.code = None + self.description = None + self.parameter = None + + def __str__(self): + return str(dict(code=self.code, description=self.description, parameter=self.parameter)) + + +class BaseError(Exception): + """Base class for exceptions in this module.""" + pass + + +class ValidationError(BaseError): + """Exception raised for errors in validation. + + Attributes: + message -- explanation of the error + """ - def __str__(self): - return str(dict(code=self.code, description=self.description, parameter=self.parameter)) + def __init__(self, message): + self.message = message diff --git a/messagebird/validation.py b/messagebird/validation.py new file mode 100644 index 0000000..0a63eb2 --- /dev/null +++ b/messagebird/validation.py @@ -0,0 +1,6 @@ +from messagebird.error import ValidationError + + +def validate_is_not_blank(value, message): + if value is None or not value.strip(): + raise ValidationError(message) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index 3876b69..f41f454 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -1,4 +1,6 @@ from messagebird.base import Base +from messagebird.error import ValidationError +from messagebird.validation import validate_is_not_blank class VoiceWebhook(Base): @@ -78,3 +80,38 @@ def __str__(self): 'items IDs : %s' % item_ids, 'count : %s' % len(item_ids) ]) + + +class VoiceCreateWebhookRequest(object): + + def __init__(self, title=None, url=None, token=None): + validate_is_not_blank(title, "title cannot be empty") + validate_is_not_blank(url, "url cannot be empty") + self._title = title + self._url = url + self.token = token + + @property + def title(self): + return self._title + + @title.setter + def title(self, value): + validate_is_not_blank(value, "title cannot be empty") + self._title = value + + @property + def url(self): + return self._url + + @url.setter + def url(self, value): + validate_is_not_blank(value, "url cannot be empty") + self._url = value + + def __str__(self): + return "\n".join([ + 'title : %s' % self.title, + 'url : %s' % self.url, + 'token : %s' % self.token, + ]) \ No newline at end of file diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index c01e979..5eb48bf 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -2,6 +2,8 @@ from messagebird import Client from messagebird.client import VOICE_WEB_HOOKS_PATH, VOICE_API_ROOT +from messagebird.error import ValidationError +from messagebird.voice_webhook import VoiceCreateWebhookRequest try: from unittest.mock import Mock @@ -13,7 +15,7 @@ class TestVoiceWebhook(unittest.TestCase): - def test_voice_webhook_read(self): + def test_voice_read_webhook(self): http_client = Mock() http_client.request.return_value = '''{ "data": [ @@ -39,3 +41,94 @@ def test_voice_webhook_read(self): self.assertEqual(webhook_id, voice_webhook.id) self.assertEqual(webhook_token, voice_webhook.token) + + def test_voice_list_webhook(self): + http_client = Mock() + http_client.request.return_value = '''{ + "data": [ + { + "id": "534e1848-235f-482d-983d-e3e11a04f58a", + "url": "https://example.com/", + "token": "foobar", + "createdAt": "2017-03-15T13:28:32Z", + "updatedAt": "2017-03-15T13:28:32Z", + "_links": { + "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" + } + }, + { + "id": "123e345-235f-482d-983d-e3e11a04f58a", + "url": "https://gogol.com/", + "token": "barbar", + "createdAt": "2017-03-15T13:28:32Z", + "updatedAt": "2017-03-15T13:28:32Z", + "_links": { + "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" + } + } + ], + "_links": { + "self": "/webhooks?page=1" + }, + "pagination": { + "totalCount": 1, + "pageCount": 1, + "currentPage": 1, + "perPage": 10 + } + }''' + + webhook_id = '534e1848-235f-482d-983d-e3e11a04f58a' + webhook_token = 'foobar' + + voice_webhook_list = Client('', http_client).voice_list_webhooks(limit=10, offset=0) + + http_client.request.assert_called_once_with( + VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '?limit=10&offset=0', 'GET', None) + + webhooks = voice_webhook_list.data + self.assertEqual(2, len(webhooks)) + self.assertEqual(webhook_id, webhooks[0].id) + self.assertEqual(webhook_token, webhooks[0].token) + + def test_voice_create_webhook(self): + http_client = Mock() + http_client.request.return_value = '' + url = "https://example.com/" + title = "FooBar" + token = "FooBarToken" + createWebhookRequest = VoiceCreateWebhookRequest(url=url, title=title, token=token) + Client('', http_client).voice_create_webhook(createWebhookRequest) + + #http_client.request.assert_called_once_with('webhooks', 'POST', create_webhook_request) + + def test_voice_create_webhook_request_validation(self): + url = "https://example.com/" + title = "FooBar" + token = "FooBarToken" + + with self.assertRaises(ValidationError): + VoiceCreateWebhookRequest(url=url) + + with self.assertRaises(ValidationError): + VoiceCreateWebhookRequest(title=title) + + request = VoiceCreateWebhookRequest(url=url, title=title) + + self.assertEqual(url, request.url) + self.assertEqual(title, request.title) + self.assertEqual(None, request.token) + + with self.assertRaises(ValidationError): + request.url = ' ' + + + + + + + def test_voice_update_webhook(self): + self.assertEqual(True, True) + + def test_voice_delete_webhook(self): + self.assertEqual(True, True) \ No newline at end of file From 0f66565ce4ae312332c83f2bebdf205a2ea40946 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 11:49:21 +0200 Subject: [PATCH 03/24] Add class VoiceUpdateWebhookRequest * Tests --- messagebird/voice_webhook.py | 15 ++++++++- tests/test_voice_webhook.py | 62 ++++++++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index f41f454..6e2771e 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -114,4 +114,17 @@ def __str__(self): 'title : %s' % self.title, 'url : %s' % self.url, 'token : %s' % self.token, - ]) \ No newline at end of file + ]) + + +class VoiceUpdateWebhookRequest(object): + + def __init__(self, title=None, token=None): + self.title = title + self.token = token + + def __str__(self): + return "\n".join([ + 'title : %s' % self.title, + 'token : %s' % self.token, + ]) diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index 5eb48bf..a756e7d 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -3,7 +3,7 @@ from messagebird import Client from messagebird.client import VOICE_WEB_HOOKS_PATH, VOICE_API_ROOT from messagebird.error import ValidationError -from messagebird.voice_webhook import VoiceCreateWebhookRequest +from messagebird.voice_webhook import VoiceCreateWebhookRequest, VoiceUpdateWebhookRequest try: from unittest.mock import Mock @@ -93,14 +93,26 @@ def test_voice_list_webhook(self): def test_voice_create_webhook(self): http_client = Mock() - http_client.request.return_value = '' - url = "https://example.com/" - title = "FooBar" - token = "FooBarToken" - createWebhookRequest = VoiceCreateWebhookRequest(url=url, title=title, token=token) - Client('', http_client).voice_create_webhook(createWebhookRequest) + http_client.request.return_value = '''{ + "data": [ + { + "id": "534e1848-235f-482d-983d-e3e11a04f58a", + "url": "https://example.com/", + "token": "foobar", + "createdAt": "2017-03-15T14:10:07Z", + "updatedAt": "2017-03-15T14:10:07Z" + } + ], + "_links": { + "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" + } + }''' + create_webhook_request = VoiceCreateWebhookRequest(url="https://example.com/", title="FooBar", token="foobar") + created_webhook = Client('', http_client).voice_create_webhook(create_webhook_request) - #http_client.request.assert_called_once_with('webhooks', 'POST', create_webhook_request) + http_client.request.assert_called_once_with(VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH, 'POST', create_webhook_request) + self.assertEqual(create_webhook_request.url, created_webhook.url) + self.assertEqual(create_webhook_request.token, created_webhook.token) def test_voice_create_webhook_request_validation(self): url = "https://example.com/" @@ -123,12 +135,36 @@ def test_voice_create_webhook_request_validation(self): request.url = ' ' + def test_voice_update_webhook(self): + http_client = Mock() + http_client.request.return_value = '''{ + "data": [ + { + "id": "534e1848-235f-482d-983d-e3e11a04f58a", + "url": "https://example.com/baz", + "token": "foobar", + "createdAt": "2017-03-15T13:27:02Z", + "updatedAt": "2017-03-15T13:28:01Z" + } + ], + "_links": { + "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" + } + }''' + webhook_id = 'webhook-id' + update_webhook_request = VoiceUpdateWebhookRequest(title="FooBar", token="foobar") + updated_webhook = Client('', http_client).voice_update_webhook(webhook_id, update_webhook_request) + http_client.request.assert_called_once_with( + VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'PUT', update_webhook_request) - - - def test_voice_update_webhook(self): - self.assertEqual(True, True) + self.assertEqual(update_webhook_request.token, updated_webhook.token) def test_voice_delete_webhook(self): - self.assertEqual(True, True) \ No newline at end of file + http_client = Mock() + http_client.request.return_value = '' + webhook_id = 'webhook-id' + Client('', http_client).voice_delete_webhook(webhook_id) + + http_client.request.assert_called_once_with( + VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'DELETE', None) From 6a327879fffbf5a796bd01f71d01b267429e6c29 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 11:51:57 +0200 Subject: [PATCH 04/24] Made _format_query static method --- messagebird/client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/messagebird/client.py b/messagebird/client.py index a41e4bd..0044257 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -454,5 +454,6 @@ def call_flow_numbers_add(self, call_flow_id, numbers=()): params = {'numbers': numbers} return CallFlowNumberList().load(self.request('call-flows/' + str(call_flow_id) + '/numbers', 'POST', params, VOICE_TYPE)) + @staticmethod def _format_query(self, limit, offset): return 'limit=' + str(limit) + '&offset=' + str(offset) From 3e3f8757425e3c9b0ae735babb1e0fdc1df405c1 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 14:58:59 +0200 Subject: [PATCH 05/24] Add [editor config](https://editorconfig.org) --- .editorconfig | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d26dfc0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,38 @@ +# https://editorconfig.org/ + +root = true + +[*] +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +charset = utf-8 + +# Docstrings and comments use max_line_length = 79 +[*.py] +max_line_length = 119 + +# Use 2 spaces for the HTML files +[*.html] +indent_size = 2 + +# The JSON files contain newlines inconsistently +[*.json] +indent_size = 2 +insert_final_newline = ignore + + +# Minified JavaScript files shouldn't be changed +[**.min.js] +indent_style = ignore +insert_final_newline = ignore + +# Makefiles always use tabs for indentation +[Makefile] +indent_style = tab + +# Batch files use tabs for indentation +[*.bat] +indent_style = tab From ca3b777f53fc6484f2ed819f5cc92b354ad7ce8d Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 15:21:33 +0200 Subject: [PATCH 06/24] Returned 4 indent spaces to editorconfig from PEP8 --- .editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index d26dfc0..73726fb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,7 +4,8 @@ root = true [*] indent_style = space -indent_size = 2 +# Python: PEP8 defines 4 spaces for indentation +indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true end_of_line = lf From 0471316ccb5baee8cc021877f2aac7df1ef8f81c Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 15:23:19 +0200 Subject: [PATCH 07/24] Client methods for voice webhooks for [docs](https://developers.messagebird.com/api/voice-calling/#webhooks) --- messagebird/client.py | 88 ++++++++++++++++++++++++++---------- messagebird/voice_webhook.py | 1 - tests/test_voice_webhook.py | 4 +- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/messagebird/client.py b/messagebird/client.py index 0044257..9b2fe14 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -7,12 +7,12 @@ from messagebird.call import Call from messagebird.call_list import CallList from messagebird.contact import Contact, ContactList -from messagebird.error import Error +from messagebird.error import Error, ValidationError from messagebird.group import Group, GroupList from messagebird.hlr import HLR from messagebird.message import Message, MessageList from messagebird.mms import MMS -from messagebird.voice_webhook import VoiceWebhook +from messagebird.voice_webhook import VoiceWebhook, VoiceWebhookList from messagebird.voicemessage import VoiceMessage from messagebird.lookup import Lookup from messagebird.verify import Verify @@ -24,7 +24,6 @@ from messagebird.voice_transcription import VoiceTranscriptionsList, VoiceTranscriptionsView from messagebird.call_flow import CallFlow, CallFlowList, CallFlowNumberList - ENDPOINT = 'https://rest.messagebird.com' CLIENT_VERSION = '1.4.1' PYTHON_VERSION = '%d.%d.%d' % (sys.version_info[0], sys.version_info[1], sys.version_info[2]) @@ -34,8 +33,6 @@ CONVERSATION_API_ROOT = 'https://conversations.messagebird.com/v1/' CONVERSATION_API_WHATSAPP_SANDBOX_ROOT = 'https://whatsapp-sandbox.messagebird.com/v1/' - - CONVERSATION_PATH = 'conversations' CONVERSATION_MESSAGES_PATH = 'messages' CONVERSATION_WEB_HOOKS_PATH = 'webhooks' @@ -56,12 +53,15 @@ def __init__(self, errors): message = ' '.join([str(e) for e in self.errors]) super(ErrorException, self).__init__(message) + class SignleErrorException(Exception): def __init__(self, errorMessage): super(SignleErrorException, self).__init__(errorMessage) + class Feature(enum.Enum): - ENABLE_CONVERSATIONS_API_WHATSAPP_SANDBOX = 1 + ENABLE_CONVERSATIONS_API_WHATSAPP_SANDBOX = 1 + class Client(object): @@ -130,7 +130,7 @@ def balance(self): """Retrieve your balance.""" return Balance().load(self.request('balance')) - def call(self,id): + def call(self, id): """Retrieve the information of a specific call""" return Call().load(self.request('calls/' + str(id), 'GET', None, VOICE_TYPE)) @@ -161,7 +161,7 @@ def call_create(self, source, destination, callFlow, webhook): Call(object) : The Call object just created.""" params = locals() - del(params['self']) + del (params['self']) return Call().load(self.request('calls', 'POST', params, VOICE_TYPE)) def call_delete(self, id): @@ -186,7 +186,7 @@ def message(self, id): def message_list(self, limit=20, offset=0): """Retrieve a list of the most recent messages.""" - query = 'limit=' + str(limit) + '&offset=' + str(offset) + query = self._format_query(limit, offset) return MessageList().load(self.request('messages?' + query)) def message_create(self, originator, recipients, body, params=None): @@ -202,7 +202,7 @@ def message_delete(self, id): """Delete a message from the dashboard.""" self.request_plain_text('messages/' + str(id), 'DELETE') - def mms_create(self, originator, recipients, body, mediaUrls, subject = None, reference = None, scheduledDatetime = None): + def mms_create(self, originator, recipients, body, mediaUrls, subject=None, reference=None, scheduledDatetime=None): """ Send bulk mms. Args: @@ -219,13 +219,13 @@ def mms_create(self, originator, recipients, body, mediaUrls, subject = None, re Returns: MMS: On success an MMS instance instantiated with success response """ - if isinstance(recipients,list): + if isinstance(recipients, list): recipients = ','.join(recipients) - if isinstance(mediaUrls,str): + if isinstance(mediaUrls, str): mediaUrls = [mediaUrls] params = locals() - del(params['self']) - return MMS().load(self.request('mms', 'POST', params)) + del (params['self']) + return MMS().load(self.request('mms', 'POST', params)) def voice_message(self, id): "Retrieve the information of a specific voice message." @@ -383,32 +383,40 @@ def conversation_read_webhook(self, id): return ConversationWebhook().load(self.request(uri, 'GET', None, CONVERSATION_TYPE)) def voice_recording_list_recordings(self, call_id, leg_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH return VoiceRecordingsList().load(self.request(uri, 'GET')) def voice_transcription_list(self, call_id, leg_id, recording_id): """List voice transcriptions.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH return VoiceTranscriptionsList().load(self.request(uri, 'GET')) def voice_transcription_download(self, call_id, leg_id, recording_id, transcriptions_file): """Download voice transcription file.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_file) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str( + recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_file) return self.request(uri, 'GET') def voice_transcription_view(self, call_id, leg_id, recording_id, transcriptions_id): """Get voice transcription data.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_id) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str( + recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_id) return VoiceTranscriptionsView().load(self.request(uri, 'GET')) def voice_transcription_create(self, call_id, leg_id, recording_id, language): """Create a voice transcription.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH params = {'language': str(language)} return VoiceTranscriptionsView().load(self.request(uri, 'POST', params, VOICE_TYPE)) def voice_recording_view(self, call_id, leg_id, recording_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) recording_response = self.request(uri, 'GET') recording_links = recording_response.get('_links') if recording_links is not None: @@ -416,7 +424,8 @@ def voice_recording_view(self, call_id, leg_id, recording_id): return VoiceRecording().load(recording_response['data'][0]) def voice_recording_download(self, call_id, leg_id, recording_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( + leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) recording_response = self.request(uri, 'GET') recording_links = recording_response.get('_links') if recording_links is None or recording_links.get('file') is None: @@ -426,9 +435,39 @@ def voice_recording_download(self, call_id, leg_id, recording_id): return VOICE_API_ROOT + recording_file def voice_read_webhook(self, id): + """ + Retrieve a voice webhook + API Reference: https://developers.messagebird.com/api/voice-calling/#webhooks + """ uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + str(id) return VoiceWebhook().load(self.request(uri, 'GET', None, VOICE_TYPE)) + def voice_list_webhooks(self, limit=10, offset=0): + """ Retrieve a list of voice webhooks. """ + uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '?' + self._format_query(limit, offset) + return VoiceWebhookList().load(self.request(uri, 'GET', None, VOICE_TYPE)) + + def voice_create_webhook(self, create_webhook_request): + """ Create a voice webhook. """ + if create_webhook_request is None: + raise ValidationError('Create request is empty') + + uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + return VoiceWebhook().load(self.request(uri, 'POST', create_webhook_request, VOICE_TYPE)) + + def voice_update_webhook(self, id, update_webhook_request): + """ Update a voice webhook. """ + if update_webhook_request is None: + raise ValidationError('Update request is empty') + + uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + str(id) + return VoiceWebhook().load(self.request(uri, 'PUT', update_webhook_request, VOICE_TYPE)) + + def voice_delete_webhook(self, id): + """ Delete a voice webhook. """ + uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + str(id) + self.request(uri, 'DELETE', None, VOICE_TYPE) + def call_flow(self, id): return CallFlow().load(self.request('call-flows/' + str(id), 'GET', None, VOICE_TYPE)) @@ -448,12 +487,13 @@ def call_flow_delete(self, id): self.request_plain_text('call-flows/' + str(id), 'DELETE', None, VOICE_TYPE) def call_flow_numbers_list(self, call_flow_id): - return CallFlowNumberList().load(self.request('call-flows/' + str(call_flow_id) + '/numbers', 'GET', None, VOICE_TYPE)) + return CallFlowNumberList().load( + self.request('call-flows/' + str(call_flow_id) + '/numbers', 'GET', None, VOICE_TYPE)) def call_flow_numbers_add(self, call_flow_id, numbers=()): params = {'numbers': numbers} - return CallFlowNumberList().load(self.request('call-flows/' + str(call_flow_id) + '/numbers', 'POST', params, VOICE_TYPE)) + return CallFlowNumberList().load( + self.request('call-flows/' + str(call_flow_id) + '/numbers', 'POST', params, VOICE_TYPE)) - @staticmethod def _format_query(self, limit, offset): return 'limit=' + str(limit) + '&offset=' + str(offset) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index 6e2771e..e534281 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -1,5 +1,4 @@ from messagebird.base import Base -from messagebird.error import ValidationError from messagebird.validation import validate_is_not_blank diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index a756e7d..525ec8f 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -110,7 +110,8 @@ def test_voice_create_webhook(self): create_webhook_request = VoiceCreateWebhookRequest(url="https://example.com/", title="FooBar", token="foobar") created_webhook = Client('', http_client).voice_create_webhook(create_webhook_request) - http_client.request.assert_called_once_with(VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH, 'POST', create_webhook_request) + http_client.request.assert_called_once_with(VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH, 'POST', + create_webhook_request) self.assertEqual(create_webhook_request.url, created_webhook.url) self.assertEqual(create_webhook_request.token, created_webhook.token) @@ -134,7 +135,6 @@ def test_voice_create_webhook_request_validation(self): with self.assertRaises(ValidationError): request.url = ' ' - def test_voice_update_webhook(self): http_client = Mock() http_client.request.return_value = '''{ From cdde607700c928d0cc5f61895365f4dd148a53c4 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 16:10:47 +0200 Subject: [PATCH 08/24] Increase coverage for voice webhooks --- messagebird/voice_webhook.py | 4 ---- tests/test_voice_webhook.py | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index e534281..6fdca03 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -3,7 +3,6 @@ class VoiceWebhook(Base): - def __init__(self): self.id = None self.url = None @@ -54,7 +53,6 @@ def __str__(self): class VoiceWebhookList(Base): - def __init__(self): self._items = None @@ -82,7 +80,6 @@ def __str__(self): class VoiceCreateWebhookRequest(object): - def __init__(self, title=None, url=None, token=None): validate_is_not_blank(title, "title cannot be empty") validate_is_not_blank(url, "url cannot be empty") @@ -117,7 +114,6 @@ def __str__(self): class VoiceUpdateWebhookRequest(object): - def __init__(self, title=None, token=None): self.title = title self.token = token diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index 525ec8f..4534223 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -119,6 +119,7 @@ def test_voice_create_webhook_request_validation(self): url = "https://example.com/" title = "FooBar" token = "FooBarToken" + blank_string = ' ' with self.assertRaises(ValidationError): VoiceCreateWebhookRequest(url=url) @@ -132,8 +133,13 @@ def test_voice_create_webhook_request_validation(self): self.assertEqual(title, request.title) self.assertEqual(None, request.token) + request.url = url + url with self.assertRaises(ValidationError): - request.url = ' ' + request.url = blank_string + + request.title = title + title + with self.assertRaises(ValidationError): + request.title = blank_string def test_voice_update_webhook(self): http_client = Mock() From 91f93999e284a685eb7793f3673d8cac6600f499 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 17:52:49 +0200 Subject: [PATCH 09/24] Fixes for create/update voice webhook requests --- messagebird/base.py | 19 ++++++++++--------- messagebird/client.py | 4 ++-- messagebird/http_client.py | 12 +++++++----- messagebird/serde.py | 8 ++++++++ messagebird/voice_webhook.py | 18 ++++++++++++++++-- tests/test_voice_webhook.py | 10 ++++++++-- 6 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 messagebird/serde.py diff --git a/messagebird/base.py b/messagebird/base.py index e64707e..e42a393 100644 --- a/messagebird/base.py +++ b/messagebird/base.py @@ -1,17 +1,18 @@ from datetime import datetime import dateutil.parser +import json class Base(object): - def load(self, data): - for name, value in list(data.items()): - if hasattr(self, name) and not callable(getattr(self,name)): - setattr(self, name, value) + def load(self, data): + for name, value in list(data.items()): + if hasattr(self, name) and not callable(getattr(self, name)): + setattr(self, name, value) - return self + return self - @staticmethod - def value_to_time(value, format='%Y-%m-%dT%H:%M:%S+00:00'): - if value is not None: - return dateutil.parser.parse(value).replace(microsecond=0) + @staticmethod + def value_to_time(value, format='%Y-%m-%dT%H:%M:%S+00:00'): + if value is not None: + return dateutil.parser.parse(value).replace(microsecond=0) diff --git a/messagebird/client.py b/messagebird/client.py index 9b2fe14..e5ca7b3 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -453,7 +453,7 @@ def voice_create_webhook(self, create_webhook_request): raise ValidationError('Create request is empty') uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH - return VoiceWebhook().load(self.request(uri, 'POST', create_webhook_request, VOICE_TYPE)) + return VoiceWebhook().load(self.request(uri, 'POST', create_webhook_request.__dict__(), VOICE_TYPE)) def voice_update_webhook(self, id, update_webhook_request): """ Update a voice webhook. """ @@ -461,7 +461,7 @@ def voice_update_webhook(self, id, update_webhook_request): raise ValidationError('Update request is empty') uri = VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + str(id) - return VoiceWebhook().load(self.request(uri, 'PUT', update_webhook_request, VOICE_TYPE)) + return VoiceWebhook().load(self.request(uri, 'PUT', update_webhook_request.__dict__(), VOICE_TYPE)) def voice_delete_webhook(self, id): """ Delete a voice webhook. """ diff --git a/messagebird/http_client.py b/messagebird/http_client.py index d82afc2..9d9218a 100644 --- a/messagebird/http_client.py +++ b/messagebird/http_client.py @@ -1,12 +1,14 @@ -import json import requests from enum import Enum +from messagebird.serde import json_serialize + try: from urllib.parse import urljoin except ImportError: from urlparse import urljoin + class ResponseFormat(Enum): text = 1 binary = 2 @@ -34,11 +36,11 @@ def request(self, path, method='GET', params=None, format=ResponseFormat.text): } method_switcher = { - 'DELETE': requests.delete(url, verify=True, headers=headers, data=json.dumps(params)), + 'DELETE': requests.delete(url, verify=True, headers=headers, data=json_serialize(params)), 'GET': requests.get(url, verify=True, headers=headers, params=params), - 'PATCH': requests.patch(url, verify=True, headers=headers, data=json.dumps(params)), - 'POST': requests.post(url, verify=True, headers=headers, data=json.dumps(params)), - 'PUT': requests.put(url, verify=True, headers=headers, data=json.dumps(params)) + 'PATCH': requests.patch(url, verify=True, headers=headers, data=json_serialize(params)), + 'POST': requests.post(url, verify=True, headers=headers, data=json_serialize(params)), + 'PUT': requests.put(url, verify=True, headers=headers, data=json_serialize(params)) } response = method_switcher.get(method, str(method) + ' is not a supported HTTP method') if isinstance(response, str): diff --git a/messagebird/serde.py b/messagebird/serde.py new file mode 100644 index 0000000..9f9f90e --- /dev/null +++ b/messagebird/serde.py @@ -0,0 +1,8 @@ +import json + + +def json_serialize(obj): + try: + return json.dumps(obj) + except TypeError: + return json.dumps(obj, default=lambda o: o.__dict__) \ No newline at end of file diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index 6fdca03..9976500 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -79,7 +79,7 @@ def __str__(self): ]) -class VoiceCreateWebhookRequest(object): +class VoiceCreateWebhookRequest(Base): def __init__(self, title=None, url=None, token=None): validate_is_not_blank(title, "title cannot be empty") validate_is_not_blank(url, "url cannot be empty") @@ -105,6 +105,13 @@ def url(self, value): validate_is_not_blank(value, "url cannot be empty") self._url = value + def __dict__(self): + return { + 'title': self.title, + 'url': self.url, + 'token': self.token + } + def __str__(self): return "\n".join([ 'title : %s' % self.title, @@ -113,11 +120,18 @@ def __str__(self): ]) -class VoiceUpdateWebhookRequest(object): +class VoiceUpdateWebhookRequest(Base): + def __init__(self, title=None, token=None): self.title = title self.token = token + def __dict__(self): + return { + 'title': self.title, + 'token': self.token + } + def __str__(self): return "\n".join([ 'title : %s' % self.title, diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index 4534223..1c3dcc2 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -1,8 +1,10 @@ +import json import unittest from messagebird import Client from messagebird.client import VOICE_WEB_HOOKS_PATH, VOICE_API_ROOT from messagebird.error import ValidationError +from messagebird.serde import json_serialize from messagebird.voice_webhook import VoiceCreateWebhookRequest, VoiceUpdateWebhookRequest try: @@ -111,7 +113,7 @@ def test_voice_create_webhook(self): created_webhook = Client('', http_client).voice_create_webhook(create_webhook_request) http_client.request.assert_called_once_with(VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH, 'POST', - create_webhook_request) + create_webhook_request.__dict__()) self.assertEqual(create_webhook_request.url, created_webhook.url) self.assertEqual(create_webhook_request.token, created_webhook.token) @@ -162,7 +164,7 @@ def test_voice_update_webhook(self): updated_webhook = Client('', http_client).voice_update_webhook(webhook_id, update_webhook_request) http_client.request.assert_called_once_with( - VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'PUT', update_webhook_request) + VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'PUT', update_webhook_request.__dict__()) self.assertEqual(update_webhook_request.token, updated_webhook.token) @@ -174,3 +176,7 @@ def test_voice_delete_webhook(self): http_client.request.assert_called_once_with( VOICE_API_ROOT + '/' + VOICE_WEB_HOOKS_PATH + '/' + webhook_id, 'DELETE', None) + + def test_check_serialization(self): + json_serialize(VoiceCreateWebhookRequest(url="https://someurl.com", title="foobar")) + json_serialize(VoiceUpdateWebhookRequest(title="foobar")) From bc8fe3283aca030305f123ed2d56c0fe31b2e1eb Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 17:53:18 +0200 Subject: [PATCH 10/24] Example for voice webhook creation --- examples/voice_create_webhook.py | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 examples/voice_create_webhook.py diff --git a/examples/voice_create_webhook.py b/examples/voice_create_webhook.py new file mode 100644 index 0000000..a7688e6 --- /dev/null +++ b/examples/voice_create_webhook.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +import argparse +import messagebird +from messagebird.voice_webhook import VoiceCreateWebhookRequest + +parser = argparse.ArgumentParser() +parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) +parser.add_argument('--url', help='url for the webhook', type=str, required=True) +parser.add_argument('--title', help='title for the webhook', type=str, required=True) +parser.add_argument('--token', help='token for the webhook', type=str) +args = vars(parser.parse_args()) + +try: + client = messagebird.Client(args['accessKey']) + + create_webhook_request = VoiceCreateWebhookRequest(url=args['url'], title=args['title'], token=args['token']) + webhook = client.voice_create_webhook(create_webhook_request) + + # Print the object information. + print('\nThe following information was returned as a Voice Webhook object:\n') + print(' id : %s' % webhook.id) + print(' token : %s' % webhook.token) + print(' url : %s' % webhook.url) + print(' createdAtDatetime : %s' % webhook.createdDatetime) + print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + +except messagebird.client.ErrorException as e: + print('An error occured while requesting a Webhook object:') + + for error in e.errors: + print(' code : %d' % error.code) + print(' description : %s' % error.description) + print(' parameter : %s\n' % error.parameter) + + + From 67917ba02628ddda20b496c9a89addab12172145 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 18:08:06 +0200 Subject: [PATCH 11/24] Add examples for crud operations on voice webhooks --- examples/voice_create_webhook.py | 2 +- examples/voice_delete_webhook.py | 24 +++++++++++++++++++++ examples/voice_list_webhook.py | 33 ++++++++++++++++++++++++++++ examples/voice_read_webhook.py | 31 ++++++++++++++++++++++++++ examples/voice_update_webhook.py | 37 ++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 examples/voice_delete_webhook.py create mode 100644 examples/voice_list_webhook.py create mode 100644 examples/voice_read_webhook.py create mode 100644 examples/voice_update_webhook.py diff --git a/examples/voice_create_webhook.py b/examples/voice_create_webhook.py index a7688e6..6d9b9ca 100644 --- a/examples/voice_create_webhook.py +++ b/examples/voice_create_webhook.py @@ -25,7 +25,7 @@ print(' updatedAtDatetime : %s' % webhook.updatedDatetime) except messagebird.client.ErrorException as e: - print('An error occured while requesting a Webhook object:') + print('An error occured while creating a Voice Webhook object:') for error in e.errors: print(' code : %d' % error.code) diff --git a/examples/voice_delete_webhook.py b/examples/voice_delete_webhook.py new file mode 100644 index 0000000..89edf5d --- /dev/null +++ b/examples/voice_delete_webhook.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +import argparse +import messagebird + +parser = argparse.ArgumentParser() +parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) +parser.add_argument('--webhookId', help='webhook that you want to update', type=str, required=True) + +args = vars(parser.parse_args()) + +try: + client = messagebird.Client(args['accessKey']) + webhook = client.voice_delete_webhook(args['webhookId']) + + # Print the object information. + print('Webhook has been deleted') + +except messagebird.client.ErrorException as e: + print('An error occured while deleting a Voice Webhook object:') + + for error in e.errors: + print(' code : %d' % error.code) + print(' description : %s' % error.description) + print(' parameter : %s\n' % error.parameter) diff --git a/examples/voice_list_webhook.py b/examples/voice_list_webhook.py new file mode 100644 index 0000000..9cb67fa --- /dev/null +++ b/examples/voice_list_webhook.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +import argparse +import messagebird +from messagebird.voice_webhook import VoiceCreateWebhookRequest + +parser = argparse.ArgumentParser() +parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) + +args = vars(parser.parse_args()) + +try: + client = messagebird.Client(args['accessKey']) + + webhooks_list = client.voice_list_webhooks() + + # Print the object information. + print('\nThe following information was returned as a Voice Webhook objects:\n') + for webhook in webhooks_list.data: + print('{') + print(' id : %s' % webhook.id) + print(' token : %s' % webhook.token) + print(' url : %s' % webhook.url) + print(' createdAtDatetime : %s' % webhook.createdDatetime) + print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + print('}\n') + +except messagebird.client.ErrorException as e: + print('An error occured while reading a Voice Webhook object:') + + for error in e.errors: + print(' code : %d' % error.code) + print(' description : %s' % error.description) + print(' parameter : %s\n' % error.parameter) diff --git a/examples/voice_read_webhook.py b/examples/voice_read_webhook.py new file mode 100644 index 0000000..2b12981 --- /dev/null +++ b/examples/voice_read_webhook.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +import argparse +import messagebird +from messagebird.voice_webhook import VoiceCreateWebhookRequest + +parser = argparse.ArgumentParser() +parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) +parser.add_argument('--webhookId', help='webhook that you want to update', type=str, required=True) + +args = vars(parser.parse_args()) + +try: + client = messagebird.Client(args['accessKey']) + + webhook = client.voice_read_webhook(args['webhookId']) + + # Print the object information. + print('\nThe following information was returned as a Voice Webhook object:\n') + print(' id : %s' % webhook.id) + print(' token : %s' % webhook.token) + print(' url : %s' % webhook.url) + print(' createdAtDatetime : %s' % webhook.createdDatetime) + print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + +except messagebird.client.ErrorException as e: + print('An error occured while reading a Voice Webhook object:') + + for error in e.errors: + print(' code : %d' % error.code) + print(' description : %s' % error.description) + print(' parameter : %s\n' % error.parameter) diff --git a/examples/voice_update_webhook.py b/examples/voice_update_webhook.py new file mode 100644 index 0000000..f73c404 --- /dev/null +++ b/examples/voice_update_webhook.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +import argparse +import messagebird +from messagebird.voice_webhook import VoiceUpdateWebhookRequest + +parser = argparse.ArgumentParser() +parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) +parser.add_argument('--webhookId', help='webhook that you want to update', type=str, required=True) +parser.add_argument('--title', help='title for the webhook', type=str) +parser.add_argument('--token', help='token for the webhook', type=str) + +args = vars(parser.parse_args()) + +try: + client = messagebird.Client(args['accessKey']) + + create_webhook_request = VoiceUpdateWebhookRequest(title=args['title'], token=args['token']) + webhook = client.voice_update_webhook(args['webhookId'], create_webhook_request) + + # Print the object information. + print('\nThe following information was returned as a Voice Webhook object:\n') + print(' id : %s' % webhook.id) + print(' token : %s' % webhook.token) + print(' url : %s' % webhook.url) + print(' createdAtDatetime : %s' % webhook.createdDatetime) + print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + +except messagebird.client.ErrorException as e: + print('An error occured while updating a Voice Webhook object:') + + for error in e.errors: + print(' code : %d' % error.code) + print(' description : %s' % error.description) + print(' parameter : %s\n' % error.parameter) + + + From 967be489619ce6aee760b53914381ea980fc8314 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 18:31:04 +0200 Subject: [PATCH 12/24] Added example of how to run examples with args to README. --- README.md | 5 +++++ examples/voice_list_webhook.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c76ec2..a2c82e4 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,11 @@ Your balance: Please see the other examples for a complete overview of all the available API calls. +To run examples with arguments, try: +```shell script +$ python ./examples/voice_create_webhook.py --accessKey accessKeyWhichNotExist --url https://example.com --title HELLO_WEBHOOK --token HELLO_TOKEN +``` + Conversations WhatsApp Sandbox ------------- To use the whatsapp sandbox you need to add `messagebird.Feature.ENABLE_CONVERSATIONS_API_WHATSAPP_SANDBOX` to the list of features you want enabled. Don't forget to replace `YOUR_ACCESS_KEY` with your actual access key. diff --git a/examples/voice_list_webhook.py b/examples/voice_list_webhook.py index 9cb67fa..ceb99b0 100644 --- a/examples/voice_list_webhook.py +++ b/examples/voice_list_webhook.py @@ -11,7 +11,7 @@ try: client = messagebird.Client(args['accessKey']) - webhooks_list = client.voice_list_webhooks() + webhooks_list = client.voice_list_webhooks(limit=5, offset=0) # Print the object information. print('\nThe following information was returned as a Voice Webhook objects:\n') From 02eede0f30a62337c15f55b4271522638fb3f3fe Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 18:56:05 +0200 Subject: [PATCH 13/24] Put requests inside method swither into lambda, to make request lazy --- messagebird/http_client.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/messagebird/http_client.py b/messagebird/http_client.py index 9d9218a..ded514a 100644 --- a/messagebird/http_client.py +++ b/messagebird/http_client.py @@ -36,15 +36,16 @@ def request(self, path, method='GET', params=None, format=ResponseFormat.text): } method_switcher = { - 'DELETE': requests.delete(url, verify=True, headers=headers, data=json_serialize(params)), - 'GET': requests.get(url, verify=True, headers=headers, params=params), - 'PATCH': requests.patch(url, verify=True, headers=headers, data=json_serialize(params)), - 'POST': requests.post(url, verify=True, headers=headers, data=json_serialize(params)), - 'PUT': requests.put(url, verify=True, headers=headers, data=json_serialize(params)) + 'DELETE': lambda: requests.delete(url, verify=True, headers=headers, data=json_serialize(params)), + 'GET': lambda: requests.get(url, verify=True, headers=headers, params=params), + 'PATCH': lambda: requests.patch(url, verify=True, headers=headers, data=json_serialize(params)), + 'POST': lambda: requests.post(url, verify=True, headers=headers, data=json_serialize(params)), + 'PUT': lambda: requests.put(url, verify=True, headers=headers, data=json_serialize(params)) } response = method_switcher.get(method, str(method) + ' is not a supported HTTP method') if isinstance(response, str): raise ValueError(response) + response = response() if response.status_code not in self.__supported_status_codes: response.raise_for_status() From b26dc2f572fdd8f90a8241c3588870603d763d4d Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Tue, 8 Oct 2019 18:56:53 +0200 Subject: [PATCH 14/24] Exit in voice webhook deletion example, if result is empty --- examples/voice_list_webhook.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/voice_list_webhook.py b/examples/voice_list_webhook.py index ceb99b0..14a1cd7 100644 --- a/examples/voice_list_webhook.py +++ b/examples/voice_list_webhook.py @@ -13,6 +13,9 @@ webhooks_list = client.voice_list_webhooks(limit=5, offset=0) + if webhooks_list is None or webhooks_list.data is None: + print("\nNo webhooks\n") + exit(0) # Print the object information. print('\nThe following information was returned as a Voice Webhook objects:\n') for webhook in webhooks_list.data: From bbe71795139a9169d8f3a23203951d8562de9586 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 09:02:40 +0200 Subject: [PATCH 15/24] Code style changes --- messagebird/client.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/messagebird/client.py b/messagebird/client.py index e5ca7b3..a14d946 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -383,34 +383,34 @@ def conversation_read_webhook(self, id): return ConversationWebhook().load(self.request(uri, 'GET', None, CONVERSATION_TYPE)) def voice_recording_list_recordings(self, call_id, leg_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ + str(leg_id) + '/' + VOICE_RECORDINGS_PATH return VoiceRecordingsList().load(self.request(uri, 'GET')) def voice_transcription_list(self, call_id, leg_id, recording_id): """List voice transcriptions.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH return VoiceTranscriptionsList().load(self.request(uri, 'GET')) def voice_transcription_download(self, call_id, leg_id, recording_id, transcriptions_file): """Download voice transcription file.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str( - recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_file) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + \ + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_file) return self.request(uri, 'GET') def voice_transcription_view(self, call_id, leg_id, recording_id, transcriptions_id): """Get voice transcription data.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str( - recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_id) + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + \ + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_id) return VoiceTranscriptionsView().load(self.request(uri, 'GET')) def voice_transcription_create(self, call_id, leg_id, recording_id, language): """Create a voice transcription.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH params = {'language': str(language)} return VoiceTranscriptionsView().load(self.request(uri, 'POST', params, VOICE_TYPE)) From 1c048b7a2f573631af360f1f2c6fc78c5a733d30 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 09:27:52 +0200 Subject: [PATCH 16/24] Fix error in documentation. URL is the only required parameter --- examples/voice_create_webhook.py | 2 +- messagebird/voice_webhook.py | 12 +----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/examples/voice_create_webhook.py b/examples/voice_create_webhook.py index 6d9b9ca..2a5ed56 100644 --- a/examples/voice_create_webhook.py +++ b/examples/voice_create_webhook.py @@ -6,7 +6,7 @@ parser = argparse.ArgumentParser() parser.add_argument('--accessKey', help='access key for MessageBird API', type=str, required=True) parser.add_argument('--url', help='url for the webhook', type=str, required=True) -parser.add_argument('--title', help='title for the webhook', type=str, required=True) +parser.add_argument('--title', help='title for the webhook', type=str) parser.add_argument('--token', help='token for the webhook', type=str) args = vars(parser.parse_args()) diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index 9976500..e4cac69 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -81,21 +81,11 @@ def __str__(self): class VoiceCreateWebhookRequest(Base): def __init__(self, title=None, url=None, token=None): - validate_is_not_blank(title, "title cannot be empty") validate_is_not_blank(url, "url cannot be empty") - self._title = title + self.title = title self._url = url self.token = token - @property - def title(self): - return self._title - - @title.setter - def title(self, value): - validate_is_not_blank(value, "title cannot be empty") - self._title = value - @property def url(self): return self._url From b7222f0b4fe6ccbf9d75944ab40310ba55b8d444 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 11:25:17 +0200 Subject: [PATCH 17/24] Fix test for VoiceCreateWebhook validation --- tests/test_voice_webhook.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index 1c3dcc2..6253acd 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -123,9 +123,6 @@ def test_voice_create_webhook_request_validation(self): token = "FooBarToken" blank_string = ' ' - with self.assertRaises(ValidationError): - VoiceCreateWebhookRequest(url=url) - with self.assertRaises(ValidationError): VoiceCreateWebhookRequest(title=title) @@ -139,10 +136,6 @@ def test_voice_create_webhook_request_validation(self): with self.assertRaises(ValidationError): request.url = blank_string - request.title = title + title - with self.assertRaises(ValidationError): - request.title = blank_string - def test_voice_update_webhook(self): http_client = Mock() http_client.request.return_value = '''{ From 4aacc146e90204adf0673be430d24148b6006705 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 15:27:51 +0200 Subject: [PATCH 18/24] Deleted editorconfig * Added python code style check in travis --- .editorconfig | 39 --------------------------------------- .travis.yml | 3 +++ 2 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 73726fb..0000000 --- a/.editorconfig +++ /dev/null @@ -1,39 +0,0 @@ -# https://editorconfig.org/ - -root = true - -[*] -indent_style = space -# Python: PEP8 defines 4 spaces for indentation -indent_size = 4 -insert_final_newline = true -trim_trailing_whitespace = true -end_of_line = lf -charset = utf-8 - -# Docstrings and comments use max_line_length = 79 -[*.py] -max_line_length = 119 - -# Use 2 spaces for the HTML files -[*.html] -indent_size = 2 - -# The JSON files contain newlines inconsistently -[*.json] -indent_size = 2 -insert_final_newline = ignore - - -# Minified JavaScript files shouldn't be changed -[**.min.js] -indent_style = ignore -insert_final_newline = ignore - -# Makefiles always use tabs for indentation -[Makefile] -indent_style = tab - -# Batch files use tabs for indentation -[*.bat] -indent_style = tab diff --git a/.travis.yml b/.travis.yml index 5c9e0e9..1beabcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,13 @@ install: - pip install requests - pip install codecov - pip install pytest pytest-cov + - pip install pycodestyle - pip install . script: - coverage run --source=messagebird -m unittest discover -s tests/ - coverage report --fail-under=80 + - pycodestyle --statistics --ignore=E121,E123,E126,E133,E226,E241,E242,E704,W503,W504,W505,E501 ./messagebird/ + - pycodestyle --statistics --ignore=E121,E123,E126,E133,E226,E241,E242,E704,W503,W504,W505,E501 ./tests/ matrix: allow_failures: - python: 'nightly' From 484456b0137b2ef401a5724fe33e10892bb7c205 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 15:29:44 +0200 Subject: [PATCH 19/24] Style fixes --- messagebird/balance.py | 9 +-- messagebird/call.py | 6 +- messagebird/call_data.py | 12 ++-- messagebird/call_flow.py | 3 +- messagebird/call_list.py | 1 - messagebird/client.py | 58 ++++++++------- messagebird/conversation_webhook.py | 1 + messagebird/formats.py | 11 +-- messagebird/hlr.py | 45 ++++++------ messagebird/http_client.py | 3 +- messagebird/lookup.py | 49 ++++++------- messagebird/message.py | 84 +++++++++++----------- messagebird/mms.py | 107 ++++++++++++++-------------- messagebird/recipient.py | 25 +++---- messagebird/serde.py | 2 +- messagebird/verify.py | 45 ++++++------ messagebird/voice_recording.py | 4 +- messagebird/voice_transcription.py | 2 +- messagebird/voicemessage.py | 79 ++++++++++---------- messagebird/webhook.py | 2 +- 20 files changed, 283 insertions(+), 265 deletions(-) diff --git a/messagebird/balance.py b/messagebird/balance.py index 33e9086..8ba8860 100644 --- a/messagebird/balance.py +++ b/messagebird/balance.py @@ -1,7 +1,8 @@ from messagebird.base import Base + class Balance(Base): - def __init__(self): - self.amount = None - self.type = None - self.payment = None + def __init__(self): + self.amount = None + self.type = None + self.payment = None diff --git a/messagebird/call.py b/messagebird/call.py index 4575d9d..e8d2a10 100644 --- a/messagebird/call.py +++ b/messagebird/call.py @@ -15,7 +15,7 @@ def __init__(self): @property def data(self): return self._data - + @data.setter def data(self, value): self._data = CallData().load(value[0]) @@ -23,5 +23,5 @@ def data(self, value): def __str__(self): return "\n".join([ 'id : %s' % self.id, - 'data.'+'data.'.join(str(self._data).splitlines(True)), - ]) \ No newline at end of file + 'data.' + 'data.'.join(str(self._data).splitlines(True)), + ]) diff --git a/messagebird/call_data.py b/messagebird/call_data.py index 2cc730d..1287e89 100644 --- a/messagebird/call_data.py +++ b/messagebird/call_data.py @@ -1,8 +1,9 @@ from messagebird.base import Base from messagebird.webhook import Webhook + class CallData(Base): - + def __init__(self): self.id = None self.status = None @@ -13,11 +14,10 @@ def __init__(self): self._endedAt = None self._webhook = None - @property def updatedAt(self): return self._updatedAt - + @updatedAt.setter def updatedAt(self, value): self._updatedAt = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') @@ -25,7 +25,7 @@ def updatedAt(self, value): @property def createdAt(self): return self._createdAt - + @createdAt.setter def createdAt(self, value): self._createdAt = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') @@ -33,7 +33,7 @@ def createdAt(self, value): @property def endedAt(self): return self._endedAt - + @endedAt.setter def endedAt(self, value): self._endedAt = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') @@ -56,4 +56,4 @@ def __str__(self): 'updatedAt : %s' % self.updatedAt, 'createdAt : %s' % self.createdAt, 'endedAt : %s' % self.endedAt, - ]) \ No newline at end of file + ]) diff --git a/messagebird/call_flow.py b/messagebird/call_flow.py index 8e61d08..2211f9d 100644 --- a/messagebird/call_flow.py +++ b/messagebird/call_flow.py @@ -60,6 +60,7 @@ def data(self, value): self._data = items + class CallFlow(Base): def __init__(self): @@ -134,4 +135,4 @@ def load(self, data): if hasattr(self, name) and not callable(getattr(self, name)): setattr(self, name, value) - return self \ No newline at end of file + return self diff --git a/messagebird/call_list.py b/messagebird/call_list.py index 0d2ec4f..e33f263 100644 --- a/messagebird/call_list.py +++ b/messagebird/call_list.py @@ -39,4 +39,3 @@ def data(self, value): if isinstance(value, list): self.count = len(value) self.items = value - diff --git a/messagebird/client.py b/messagebird/client.py index a14d946..dbcf778 100644 --- a/messagebird/client.py +++ b/messagebird/client.py @@ -191,7 +191,8 @@ def message_list(self, limit=20, offset=0): def message_create(self, originator, recipients, body, params=None): """Create a new message.""" - if params is None: params = {} + if params is None: + params = {} if type(recipients) == list: recipients = ','.join(recipients) @@ -233,7 +234,8 @@ def voice_message(self, id): def voice_message_create(self, recipients, body, params=None): """Create a new voice message.""" - if params is None: params = {} + if params is None: + params = {} if type(recipients) == list: recipients = ','.join(recipients) @@ -242,17 +244,20 @@ def voice_message_create(self, recipients, body, params=None): def lookup(self, phonenumber, params=None): """Do a new lookup.""" - if params is None: params = {} + if params is None: + params = {} return Lookup().load(self.request('lookup/' + str(phonenumber), 'GET', params)) def lookup_hlr(self, phonenumber, params=None): """Retrieve the information of a specific HLR lookup.""" - if params is None: params = {} + if params is None: + params = {} return HLR().load(self.request('lookup/' + str(phonenumber) + '/hlr', 'GET', params)) def lookup_hlr_create(self, phonenumber, params=None): """Perform a new HLR lookup.""" - if params is None: params = {} + if params is None: + params = {} return HLR().load(self.request('lookup/' + str(phonenumber) + '/hlr', 'POST', params)) def verify(self, id): @@ -261,7 +266,8 @@ def verify(self, id): def verify_create(self, recipient, params=None): """Create a new verification.""" - if params is None: params = {} + if params is None: + params = {} params.update({'recipient': recipient}) return Verify().load(self.request('verify', 'POST', params)) @@ -278,7 +284,8 @@ def contact(self, id): return Contact().load(self.request('contacts/' + str(id))) def contact_create(self, phonenumber, params=None): - if params is None: params = {} + if params is None: + params = {} params.update({'msisdn': phonenumber}) return Contact().load(self.request('contacts', 'POST', params)) @@ -296,7 +303,8 @@ def group(self, id): return Group().load(self.request('groups/' + str(id), 'GET', None)) def group_create(self, name, params=None): - if params is None: params = {} + if params is None: + params = {} params.update({'name': name}) return Group().load(self.request('groups', 'POST', params)) @@ -308,7 +316,8 @@ def group_list(self, limit=10, offset=0): return GroupList().load(self.request('groups?' + query, 'GET', None)) def group_update(self, id, name, params=None): - if params is None: params = {} + if params is None: + params = {} params.update({'name': name}) self.request_plain_text('groups/' + str(id), 'PATCH', params) @@ -383,40 +392,32 @@ def conversation_read_webhook(self, id): return ConversationWebhook().load(self.request(uri, 'GET', None, CONVERSATION_TYPE)) def voice_recording_list_recordings(self, call_id, leg_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ - str(leg_id) + '/' + VOICE_RECORDINGS_PATH + uri = self.generate_voice_calls_url(call_id=call_id, leg_id=leg_id) return VoiceRecordingsList().load(self.request(uri, 'GET')) def voice_transcription_list(self, call_id, leg_id, recording_id): """List voice transcriptions.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ - str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = self.generate_voice_calls_url(call_id, leg_id, recording_id) return VoiceTranscriptionsList().load(self.request(uri, 'GET')) def voice_transcription_download(self, call_id, leg_id, recording_id, transcriptions_file): """Download voice transcription file.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ - str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + \ - str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_file) + uri = self.generate_voice_calls_url(call_id, leg_id, recording_id) + '/' + str(transcriptions_file) return self.request(uri, 'GET') def voice_transcription_view(self, call_id, leg_id, recording_id, transcriptions_id): """Get voice transcription data.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ - str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + \ - str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + '/' + str(transcriptions_id) + uri = self.generate_voice_calls_url(call_id, leg_id, recording_id) + '/' + str(transcriptions_id) return VoiceTranscriptionsView().load(self.request(uri, 'GET')) def voice_transcription_create(self, call_id, leg_id, recording_id, language): """Create a voice transcription.""" - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + \ - str(leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + uri = self.generate_voice_calls_url(call_id, leg_id, recording_id) params = {'language': str(language)} return VoiceTranscriptionsView().load(self.request(uri, 'POST', params, VOICE_TYPE)) def voice_recording_view(self, call_id, leg_id, recording_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + uri = self.generate_voice_calls_url(call_id=call_id, leg_id=leg_id) + '/' + str(recording_id) recording_response = self.request(uri, 'GET') recording_links = recording_response.get('_links') if recording_links is not None: @@ -424,8 +425,7 @@ def voice_recording_view(self, call_id, leg_id, recording_id): return VoiceRecording().load(recording_response['data'][0]) def voice_recording_download(self, call_id, leg_id, recording_id): - uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str( - leg_id) + '/' + VOICE_RECORDINGS_PATH + '/' + str(recording_id) + uri = self.generate_voice_calls_url(call_id=call_id, leg_id=leg_id) + '/' + str(recording_id) recording_response = self.request(uri, 'GET') recording_links = recording_response.get('_links') if recording_links is None or recording_links.get('file') is None: @@ -497,3 +497,11 @@ def call_flow_numbers_add(self, call_flow_id, numbers=()): def _format_query(self, limit, offset): return 'limit=' + str(limit) + '&offset=' + str(offset) + + @staticmethod + def generate_voice_calls_url(call_id=None, leg_id=None, recording_id=None): + uri = VOICE_API_ROOT + '/' + VOICE_PATH + '/' + uri += str(call_id) + '/' + VOICE_LEGS_PATH + '/' + str(leg_id) + '/' + VOICE_RECORDINGS_PATH + if recording_id: + uri += '/' + str(recording_id) + '/' + VOICE_TRANSCRIPTIONS_PATH + return uri diff --git a/messagebird/conversation_webhook.py b/messagebird/conversation_webhook.py index 68e924d..4b581d3 100644 --- a/messagebird/conversation_webhook.py +++ b/messagebird/conversation_webhook.py @@ -44,6 +44,7 @@ def __str__(self): 'updated date time : %s' % self.updatedDatetime ]) + class ConversationWebhookList(Base): def __init__(self): self.offset = None diff --git a/messagebird/formats.py b/messagebird/formats.py index c45aa0d..83c7748 100644 --- a/messagebird/formats.py +++ b/messagebird/formats.py @@ -1,8 +1,9 @@ from messagebird.base import Base + class Formats(Base): - def __init__(self): - self.e164 = None - self.international = None - self.national = None - self.rfc3966 = None + def __init__(self): + self.e164 = None + self.international = None + self.national = None + self.rfc3966 = None diff --git a/messagebird/hlr.py b/messagebird/hlr.py index c0623c9..0b41ad0 100644 --- a/messagebird/hlr.py +++ b/messagebird/hlr.py @@ -1,29 +1,30 @@ from messagebird.base import Base + class HLR(Base): - def __init__(self): - self.id = None - self.href = None - self.msisdn = None - self.network = None - self.reference = None - self.status = None - self.details = None - self._createdDatetime = None - self._statusDatetime = None + def __init__(self): + self.id = None + self.href = None + self.msisdn = None + self.network = None + self.reference = None + self.status = None + self.details = None + self._createdDatetime = None + self._statusDatetime = None - @property - def createdDatetime(self): - return self._createdDatetime + @property + def createdDatetime(self): + return self._createdDatetime - @createdDatetime.setter - def createdDatetime(self, value): - self._createdDatetime = self.value_to_time(value) + @createdDatetime.setter + def createdDatetime(self, value): + self._createdDatetime = self.value_to_time(value) - @property - def statusDatetime(self): - return self._statusDatetime + @property + def statusDatetime(self): + return self._statusDatetime - @statusDatetime.setter - def statusDatetime(self, value): - self._statusDatetime = self.value_to_time(value) + @statusDatetime.setter + def statusDatetime(self, value): + self._statusDatetime = self.value_to_time(value) diff --git a/messagebird/http_client.py b/messagebird/http_client.py index ded514a..c25148f 100644 --- a/messagebird/http_client.py +++ b/messagebird/http_client.py @@ -26,7 +26,8 @@ def __init__(self, endpoint, access_key, user_agent): def request(self, path, method='GET', params=None, format=ResponseFormat.text): """Builds a request and gets a response.""" - if params is None: params = {} + if params is None: + params = {} url = urljoin(self.endpoint, path) headers = { 'Accept': 'application/json', diff --git a/messagebird/lookup.py b/messagebird/lookup.py index 006eb77..e3c9994 100644 --- a/messagebird/lookup.py +++ b/messagebird/lookup.py @@ -1,32 +1,33 @@ -from messagebird.base import Base +from messagebird.base import Base from messagebird.formats import Formats -from messagebird.hlr import HLR +from messagebird.hlr import HLR + class Lookup(Base): - def __init__(self): - self.href = None - self.countryCode = None - self.countryPrefix = None - self.phoneNumber = None - self.type = None - self._formats = None - self._hlr = None + def __init__(self): + self.href = None + self.countryCode = None + self.countryPrefix = None + self.phoneNumber = None + self.type = None + self._formats = None + self._hlr = None - def __str__(self): - return str(self.__class__) + ": " + str(self.__dict__) + def __str__(self): + return str(self.__class__) + ": " + str(self.__dict__) - @property - def formats(self): - return self._formats + @property + def formats(self): + return self._formats - @formats.setter - def formats(self, value): - self._formats = Formats().load(value) + @formats.setter + def formats(self, value): + self._formats = Formats().load(value) - @property - def hlr(self): - return self._hlr + @property + def hlr(self): + return self._hlr - @hlr.setter - def hlr(self, value): - self._hlr = HLR().load(value) + @hlr.setter + def hlr(self, value): + self._hlr = HLR().load(value) diff --git a/messagebird/message.py b/messagebird/message.py index 24b1fbf..33e60f2 100644 --- a/messagebird/message.py +++ b/messagebird/message.py @@ -1,4 +1,4 @@ -from messagebird.base import Base +from messagebird.base import Base from messagebird.base_list import BaseList from messagebird.recipient import Recipient @@ -10,44 +10,44 @@ def __init__(self): class Message(Base): - def __init__(self): - self.id = None - self.href = None - self.direction = None - self.type = None - self.originator = None - self.body = None - self.reference = None - self.validity = None - self.gateway = None - self.typeDetails = None - self.datacoding = None - self.mclass = None - self._scheduledDatetime = None - self._createdDatetime = None - self._recipients = None - - @property - def scheduledDatetime(self): - return self._scheduledDatetime - - @scheduledDatetime.setter - def scheduledDatetime(self, value): - self._scheduledDatetime = self.value_to_time(value) - - @property - def createdDatetime(self): - return self._createdDatetime - - @createdDatetime.setter - def createdDatetime(self, value): - self._createdDatetime = self.value_to_time(value) - - @property - def recipients(self): - return self._recipients - - @recipients.setter - def recipients(self, value): - value['items'] = [Recipient().load(r) for r in value['items']] - self._recipients = value + def __init__(self): + self.id = None + self.href = None + self.direction = None + self.type = None + self.originator = None + self.body = None + self.reference = None + self.validity = None + self.gateway = None + self.typeDetails = None + self.datacoding = None + self.mclass = None + self._scheduledDatetime = None + self._createdDatetime = None + self._recipients = None + + @property + def scheduledDatetime(self): + return self._scheduledDatetime + + @scheduledDatetime.setter + def scheduledDatetime(self, value): + self._scheduledDatetime = self.value_to_time(value) + + @property + def createdDatetime(self): + return self._createdDatetime + + @createdDatetime.setter + def createdDatetime(self, value): + self._createdDatetime = self.value_to_time(value) + + @property + def recipients(self): + return self._recipients + + @recipients.setter + def recipients(self, value): + value['items'] = [Recipient().load(r) for r in value['items']] + self._recipients = value diff --git a/messagebird/mms.py b/messagebird/mms.py index 39ffe97..aa4682a 100644 --- a/messagebird/mms.py +++ b/messagebird/mms.py @@ -1,56 +1,57 @@ -from messagebird.base import Base +from messagebird.base import Base from messagebird.recipient import Recipient + class MMS(Base): - def __init__(self): - self.id = None - self.href = None - self.direction = None - self.originator = None - self.subject = None - self.body = None - self.mediaUrls = None - self.reference = None - self._scheduledDatetime = None - self._createdDatetime = None - self._recipients = None - - @property - def scheduledDatetime(self): - return self._scheduledDatetime - - @scheduledDatetime.setter - def scheduledDatetime(self, value): - self._scheduledDatetime = self.value_to_time(value) - - @property - def createdDatetime(self): - return self._createdDatetime - - @createdDatetime.setter - def createdDatetime(self, value): - self._createdDatetime = self.value_to_time(value) - - @property - def recipients(self): - return self._recipients - - @recipients.setter - def recipients(self, value): - value['items'] = [Recipient().load(r) for r in value['items']] - self._recipients = value - - def __str__(self): - return "\n".join([ - "id : %s" % self.id , - "href : %s" % self.href , - "direction : %s" % self.direction , - "originator : %s" % self.originator , - "subject : %s" % self.subject , - "body : %s" % self.body , - "mediaUrls : %s" % ",".join(self.mediaUrls), - "reference : %s" % self.reference , - "scheduledDatetime : %s" % self.scheduledDatetime , - "createdDatetime : %s" % self.createdDatetime , - "recipients : %s" % self.recipients, - ]) \ No newline at end of file + def __init__(self): + self.id = None + self.href = None + self.direction = None + self.originator = None + self.subject = None + self.body = None + self.mediaUrls = None + self.reference = None + self._scheduledDatetime = None + self._createdDatetime = None + self._recipients = None + + @property + def scheduledDatetime(self): + return self._scheduledDatetime + + @scheduledDatetime.setter + def scheduledDatetime(self, value): + self._scheduledDatetime = self.value_to_time(value) + + @property + def createdDatetime(self): + return self._createdDatetime + + @createdDatetime.setter + def createdDatetime(self, value): + self._createdDatetime = self.value_to_time(value) + + @property + def recipients(self): + return self._recipients + + @recipients.setter + def recipients(self, value): + value['items'] = [Recipient().load(r) for r in value['items']] + self._recipients = value + + def __str__(self): + return "\n".join([ + "id : %s" % self.id, + "href : %s" % self.href, + "direction : %s" % self.direction, + "originator : %s" % self.originator, + "subject : %s" % self.subject, + "body : %s" % self.body, + "mediaUrls : %s" % ",".join(self.mediaUrls), + "reference : %s" % self.reference, + "scheduledDatetime : %s" % self.scheduledDatetime, + "createdDatetime : %s" % self.createdDatetime, + "recipients : %s" % self.recipients, + ]) diff --git a/messagebird/recipient.py b/messagebird/recipient.py index 1764e5f..4064159 100644 --- a/messagebird/recipient.py +++ b/messagebird/recipient.py @@ -1,15 +1,16 @@ from messagebird.base import Base + class Recipient(Base): - def __init__(self): - self.recipient = None - self.status = None - self._statusDatetime = None - - @property - def statusDatetime(self): - return self._statusDatetime - - @statusDatetime.setter - def statusDatetime(self, value): - self._statusDatetime = self.value_to_time(value) + def __init__(self): + self.recipient = None + self.status = None + self._statusDatetime = None + + @property + def statusDatetime(self): + return self._statusDatetime + + @statusDatetime.setter + def statusDatetime(self, value): + self._statusDatetime = self.value_to_time(value) diff --git a/messagebird/serde.py b/messagebird/serde.py index 9f9f90e..cd86c1e 100644 --- a/messagebird/serde.py +++ b/messagebird/serde.py @@ -5,4 +5,4 @@ def json_serialize(obj): try: return json.dumps(obj) except TypeError: - return json.dumps(obj, default=lambda o: o.__dict__) \ No newline at end of file + return json.dumps(obj, default=lambda o: o.__dict__) diff --git a/messagebird/verify.py b/messagebird/verify.py index 972643b..299b645 100644 --- a/messagebird/verify.py +++ b/messagebird/verify.py @@ -1,30 +1,29 @@ from messagebird.base import Base -class Verify(Base): - def __init__(self): - self.id = None - self.href = None - self.recipient = None - self.reference = None - self.messages = None - self.status = None - self._createdDatetime = None - self._validUntilDatetime = None - - @property - def createdDatetime(self): - return self._createdDatetime +class Verify(Base): + def __init__(self): + self.id = None + self.href = None + self.recipient = None + self.reference = None + self.messages = None + self.status = None + self._createdDatetime = None + self._validUntilDatetime = None - @createdDatetime.setter - def createdDatetime(self, value): - self._createdDatetime = self.value_to_time(value) + @property + def createdDatetime(self): + return self._createdDatetime + @createdDatetime.setter + def createdDatetime(self, value): + self._createdDatetime = self.value_to_time(value) - @property - def validUntilDatetime(self): - return self._validUntilDatetime + @property + def validUntilDatetime(self): + return self._validUntilDatetime - @validUntilDatetime.setter - def validUntilDatetime(self, value): - self._validUntilDatetime = self.value_to_time(value) + @validUntilDatetime.setter + def validUntilDatetime(self, value): + self._validUntilDatetime = self.value_to_time(value) diff --git a/messagebird/voice_recording.py b/messagebird/voice_recording.py index a1c228e..22db896 100644 --- a/messagebird/voice_recording.py +++ b/messagebird/voice_recording.py @@ -1,5 +1,6 @@ from messagebird.base import Base + class VoiceRecording(Base): def __init__(self): @@ -44,6 +45,7 @@ def __str__(self): 'links : %s' % self._links ]) + class VoiceRecordingsList(Base): def __init__(self): self._items = None @@ -55,7 +57,7 @@ def data(self): @data.setter def data(self, value): if isinstance(value, list): - self._items = [] + self._items = [] for item in value: self._items.append(VoiceRecording().load(item)) diff --git a/messagebird/voice_transcription.py b/messagebird/voice_transcription.py index 96a290e..0880866 100644 --- a/messagebird/voice_transcription.py +++ b/messagebird/voice_transcription.py @@ -51,4 +51,4 @@ def data(self): @data.setter def data(self, value): if isinstance(value, list): - self.items = value \ No newline at end of file + self.items = value diff --git a/messagebird/voicemessage.py b/messagebird/voicemessage.py index a8630d4..27a5a1f 100644 --- a/messagebird/voicemessage.py +++ b/messagebird/voicemessage.py @@ -1,42 +1,43 @@ -from messagebird.base import Base +from messagebird.base import Base from messagebird.recipient import Recipient + class VoiceMessage(Base): - def __init__(self): - self.id = None - self.href = None - self.originator = None - self.body = None - self.reference = None - self.language = None - self.voice = None - self.repeat = None - self.ifMachine = None - self._scheduledDatetime = None - self._createdDatetime = None - self._recipients = None - - @property - def scheduledDatetime(self): - return self._scheduledDatetime - - @scheduledDatetime.setter - def scheduledDatetime(self, value): - self._scheduledDatetime = self.value_to_time(value) - - @property - def createdDatetime(self): - return self._createdDatetime - - @createdDatetime.setter - def createdDatetime(self, value): - self._createdDatetime = self.value_to_time(value) - - @property - def recipients(self): - return self._recipients - - @recipients.setter - def recipients(self, value): - value['items'] = [Recipient().load(r) for r in value['items']] - self._recipients = value + def __init__(self): + self.id = None + self.href = None + self.originator = None + self.body = None + self.reference = None + self.language = None + self.voice = None + self.repeat = None + self.ifMachine = None + self._scheduledDatetime = None + self._createdDatetime = None + self._recipients = None + + @property + def scheduledDatetime(self): + return self._scheduledDatetime + + @scheduledDatetime.setter + def scheduledDatetime(self, value): + self._scheduledDatetime = self.value_to_time(value) + + @property + def createdDatetime(self): + return self._createdDatetime + + @createdDatetime.setter + def createdDatetime(self, value): + self._createdDatetime = self.value_to_time(value) + + @property + def recipients(self): + return self._recipients + + @recipients.setter + def recipients(self, value): + value['items'] = [Recipient().load(r) for r in value['items']] + self._recipients = value diff --git a/messagebird/webhook.py b/messagebird/webhook.py index 28c0e7b..3516e82 100644 --- a/messagebird/webhook.py +++ b/messagebird/webhook.py @@ -8,7 +8,7 @@ def __init__(self): self.token = None def __str__(self): - return "\n".join([ + return "\n".join([ 'url : %s' % self.url, 'token : %s' % self.token, ]) From 06e38d4921a8ae7d0e012a2ab14d2b2ca0468326 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Wed, 9 Oct 2019 15:36:38 +0200 Subject: [PATCH 20/24] Style fixes for tests --- tests/test_call_flow.py | 192 +++++++++++++++-------------- tests/test_contact.py | 7 +- tests/test_conversation_webhook.py | 22 ++-- tests/test_group.py | 3 +- tests/test_message.py | 15 ++- tests/test_mms.py | 9 +- tests/test_verify.py | 1 - tests/test_voice_recording.py | 38 ++++-- tests/test_voice_transcription.py | 2 +- tests/test_voicemessage.py | 14 ++- 10 files changed, 176 insertions(+), 127 deletions(-) diff --git a/tests/test_call_flow.py b/tests/test_call_flow.py index 53503a2..fe06886 100644 --- a/tests/test_call_flow.py +++ b/tests/test_call_flow.py @@ -14,28 +14,28 @@ class TestCallFlow(unittest.TestCase): def test_get_flow(self): http_client = Mock() http_client.request.return_value = '''{ - "data": [ - { - "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", - "title": "Updated call flow", - "record": false, - "steps": [ - { - "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", - "action": "transfer", - "options": { - "destination": "31611223344" + "data": [ + { + "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", + "title": "Updated call flow", + "record": false, + "steps": [ + { + "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", + "action": "transfer", + "options": { + "destination": "31611223344" + } + } + ], + "createdAt": "2017-03-06T13:34:14Z", + "updatedAt": "2017-03-06T15:02:38Z" + } + ], + "_links": { + "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635" } } - ], - "createdAt": "2017-03-06T13:34:14Z", - "updatedAt": "2017-03-06T15:02:38Z" - } - ], - "_links": { - "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635" - } -} ''' call_flow = Client('', http_client).call_flow('de3ed163-d5fc-45f4-b8c4-7eea7458c635') @@ -47,56 +47,56 @@ def test_get_flow(self): def test_get_flow_list(self): http_client = Mock() http_client.request.return_value = '''{ - "data": [ - { - "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", - "title": "Forward call to 31612345678", - "record": false, - "steps": [ - { - "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", - "action": "transfer", - "options": { - "destination": "31612345678" + "data": [ + { + "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", + "title": "Forward call to 31612345678", + "record": false, + "steps": [ + { + "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", + "action": "transfer", + "options": { + "destination": "31612345678" + } + } + ], + "createdAt": "2017-03-06T13:34:14Z", + "updatedAt": "2017-03-06T13:34:14Z", + "_links": { + "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635" + } + }, + { + "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c634", + "title": "Forward call to 0600123123", + "record": true, + "steps": [ + { + "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", + "action": "transfer", + "options": { + "destination": "31612345678" + } + } + ], + "createdAt": "2017-03-06T13:34:14Z", + "updatedAt": "2017-03-06T13:34:14Z", + "_links": { + "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c634" + } + } + ], + "_links": { + "self": "/call-flows?page=1" + }, + "pagination": { + "totalCount": 2, + "pageCount": 2, + "currentPage": 1, + "perPage": 10 } } - ], - "createdAt": "2017-03-06T13:34:14Z", - "updatedAt": "2017-03-06T13:34:14Z", - "_links": { - "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635" - } - }, - { - "id": "de3ed163-d5fc-45f4-b8c4-7eea7458c634", - "title": "Forward call to 0600123123", - "record": true, - "steps": [ - { - "id": "3538a6b8-5a2e-4537-8745-f72def6bd393", - "action": "transfer", - "options": { - "destination": "31612345678" - } - } - ], - "createdAt": "2017-03-06T13:34:14Z", - "updatedAt": "2017-03-06T13:34:14Z", - "_links": { - "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c634" - } - } - ], - "_links": { - "self": "/call-flows?page=1" - }, - "pagination": { - "totalCount": 2, - "pageCount": 2, - "currentPage": 1, - "perPage": 10 - } -} ''' call_flow_list = Client('', http_client).call_flow_list(20, 0) @@ -109,33 +109,34 @@ def test_get_flow_list(self): def test_numbers_list(self): http_client = Mock() http_client.request.return_value = '''{ - "data": [ - { - "id": "13f38f34-7ff4-45b3-8783-8d5b1143f22b", - "number": "31611111111", - "callFlowId": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", - "createdAt": "2017-03-16T13:49:24Z", - "updatedAt": "2017-09-12T08:59:50Z", - "_links": { - "self": "/numbers/13f38f34-7ff4-45b3-8783-8d5b1143f22b" - } - } - ], - "_links": { - "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers?page=1" - }, - "pagination": { - "totalCount": 1, - "pageCount": 1, - "currentPage": 1, - "perPage": 10 - } -} + "data": [ + { + "id": "13f38f34-7ff4-45b3-8783-8d5b1143f22b", + "number": "31611111111", + "callFlowId": "de3ed163-d5fc-45f4-b8c4-7eea7458c635", + "createdAt": "2017-03-16T13:49:24Z", + "updatedAt": "2017-09-12T08:59:50Z", + "_links": { + "self": "/numbers/13f38f34-7ff4-45b3-8783-8d5b1143f22b" + } + } + ], + "_links": { + "self": "/call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers?page=1" + }, + "pagination": { + "totalCount": 1, + "pageCount": 1, + "currentPage": 1, + "perPage": 10 + } + } ''' number_list = Client('', http_client).call_flow_numbers_list('de3ed163-d5fc-45f4-b8c4-7eea7458c635') - http_client.request.assert_called_once_with('call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers', 'GET', None) + http_client.request.assert_called_once_with('call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers', 'GET', + None) self.assertEqual('31611111111', number_list.data[0].number) self.assertEqual(1, number_list.pagination['totalCount']) @@ -144,9 +145,12 @@ def test_numbers_add(self): http_client = Mock() http_client.request.return_value = '{}' - Client('', http_client).call_flow_numbers_add('de3ed163-d5fc-45f4-b8c4-7eea7458c635', - ['31611111111', '31611111112']) + Client('', http_client).call_flow_numbers_add( + 'de3ed163-d5fc-45f4-b8c4-7eea7458c635', + ['31611111111', '31611111112'] + ) params = {'numbers': ['31611111111', '31611111112']} - http_client.request.assert_called_once_with('call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers', 'POST', params) \ No newline at end of file + http_client.request.assert_called_once_with( + 'call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers', 'POST', params) diff --git a/tests/test_contact.py b/tests/test_contact.py index 12c265c..060e163 100644 --- a/tests/test_contact.py +++ b/tests/test_contact.py @@ -30,7 +30,8 @@ def test_contact_create(self): Client('', http_client).contact_create(31612345678, {'firstName': 'Foo', 'custom3': 'Third'}) - http_client.request.assert_called_once_with('contacts', 'POST', {'msisdn': 31612345678, 'firstName': 'Foo', 'custom3': 'Third'}) + http_client.request.assert_called_once_with( + 'contacts', 'POST', {'msisdn': 31612345678, 'firstName': 'Foo', 'custom3': 'Third'}) def test_contact_delete(self): http_client = Mock() @@ -55,7 +56,9 @@ def test_contact_update(self): Client('', http_client).contact_update('contact-id', {'msisdn': 31687654321, 'custom4': 'fourth'}) - http_client.request.assert_called_once_with('contacts/contact-id', 'PATCH', {'msisdn': 31687654321, 'custom4': 'fourth'}) + http_client.request.assert_called_once_with( + 'contacts/contact-id', 'PATCH', {'msisdn': 31687654321, 'custom4': 'fourth'} + ) def test_contact_list(self): http_client = Mock() diff --git a/tests/test_conversation_webhook.py b/tests/test_conversation_webhook.py index f329194..01dc68b 100644 --- a/tests/test_conversation_webhook.py +++ b/tests/test_conversation_webhook.py @@ -70,16 +70,16 @@ def test_conversation_webhook_read(self): def test_conversation_webhook_update(self): http_client = Mock() http_client.request.return_value = json.dumps({"id": "985ae50937a94c64b392531ea87a0263", - "url": "https://example.com/webhook", - "channelId": "853eeb5348e541a595da93b48c61a1ae", - "events": [ - "message.created", - "message.updated", - ], - "status": "enabled", - "createdDatetime": "2018-08-29T10:04:23Z", - "updatedDatetime": "2018-08-29T10:10:23Z" - }) + "url": "https://example.com/webhook", + "channelId": "853eeb5348e541a595da93b48c61a1ae", + "events": [ + "message.created", + "message.updated", + ], + "status": "enabled", + "createdDatetime": "2018-08-29T10:04:23Z", + "updatedDatetime": "2018-08-29T10:10:23Z" + }) webhookRequestData = { 'events': [CONVERSATION_WEBHOOK_EVENT_CONVERSATION_CREATED, @@ -88,4 +88,4 @@ def test_conversation_webhook_update(self): 'status': 'enabled' } web_hook = Client('', http_client).conversation_update_webhook('webhook-id', webhookRequestData) - http_client.request.assert_called_once_with('webhooks/webhook-id', 'PATCH', webhookRequestData) \ No newline at end of file + http_client.request.assert_called_once_with('webhooks/webhook-id', 'PATCH', webhookRequestData) diff --git a/tests/test_group.py b/tests/test_group.py index b75d109..581ee82 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -64,7 +64,8 @@ def test_group_add_contacts(self): Client('', http_client).group_add_contacts('group-id', ['contact-id', 'other-contact-id']) - http_client.request.assert_called_once_with('groups/group-id?ids[]=contact-id&ids[]=other-contact-id', 'PUT', None) + http_client.request.assert_called_once_with('groups/group-id?ids[]=contact-id&ids[]=other-contact-id', 'PUT', + None) def test_group_remove_contact(self): http_client = Mock() diff --git a/tests/test_message.py b/tests/test_message.py index 6bd0d3b..38013da 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -25,9 +25,18 @@ def test_message_create(self): http_client = Mock() http_client.request.return_value = '{}' - Client('', http_client).message_create('MessageBird', ['31612345678', '31687654321'], 'Hello World', {'datacoding': 'unicode'}) - - http_client.request.assert_called_once_with('messages', 'POST', {'datacoding': 'unicode', 'originator': 'MessageBird', 'body': 'Hello World', 'recipients': '31612345678,31687654321' }) + Client('', http_client).message_create( + 'MessageBird', ['31612345678', '31687654321'], 'Hello World', {'datacoding': 'unicode'}) + + http_client.request.assert_called_once_with( + 'messages', 'POST', + { + 'datacoding': 'unicode', + 'originator': 'MessageBird', + 'body': 'Hello World', + 'recipients': '31612345678,31687654321' + } + ) def test_message_delete(self): http_client = Mock() diff --git a/tests/test_mms.py b/tests/test_mms.py index 61ba3b0..6685458 100644 --- a/tests/test_mms.py +++ b/tests/test_mms.py @@ -15,7 +15,12 @@ def test_create_mms(self): http_client = Mock() http_client.request.return_value = '{"originator": "test-org", "body": "Rich test message", "direction": "mt", "recipients": {"totalCount": 1, "totalSentCount": 1, "totalDeliveredCount": 0, "totalDeliveryFailedCount": 0, "items": [{"status": "sent", "statusDatetime": "2019-06-04T13:54:48+00:00", "recipient": 4915238456487}]}, "reference": null, "createdDatetime": "2019-06-04T13:54:48+00:00", "href": "https://rest.messagebird.com/mms/0a75f8f82b5d4377bd8fb5b22ac1e8ac", "mediaUrls": ["https://www.messagebird.com/assets/images/og/messagebird.gif"], "scheduledDatetime": null, "id": "0a75f8f82b5d4377bd8fb5b22ac1e8ac", "subject": null}' - params = {"originator": "test-org", "body": "Rich test message","recipients":"+4915238456487","mediaUrls":"https://www.messagebird.com/assets/images/og/messagebird.gif"} + params = { + "originator": "test-org", + "body": "Rich test message", + "recipients": "+4915238456487", + "mediaUrls": "https://www.messagebird.com/assets/images/og/messagebird.gif" + } mms = Client('', http_client).mms_create(**params) params["mediaUrls"] = [params["mediaUrls"]] @@ -24,4 +29,4 @@ def test_create_mms(self): self.assertEqual(params["originator"], mms.originator) self.assertEqual(params["recipients"].strip("+"), str(mms.recipients["items"][0].recipient)) - self.assertEqual(1,len(mms.recipients["items"])) + self.assertEqual(1, len(mms.recipients["items"])) diff --git a/tests/test_verify.py b/tests/test_verify.py index cd46ae9..da9d215 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -55,4 +55,3 @@ def test_verify_delete_invalid(self): Client('', http_client).verify_delete('non-existent-verify-id') http_client.request.assert_called_once_with('verify/non-existent-verify-id', 'DELETE', None) - diff --git a/tests/test_voice_recording.py b/tests/test_voice_recording.py index d140b72..628bfa2 100644 --- a/tests/test_voice_recording.py +++ b/tests/test_voice_recording.py @@ -19,9 +19,15 @@ def test_voice_recording_view(self): http_client = Mock() http_client.request.return_value = '{"data":[{"id":"12345678-9012-3456-7890-123456789012","format":"wav","legId":"87654321-0987-6543-2109-876543210987","status":"done","duration":32,"type":"transfer","createdAt":"2018-01-01T00:00:01Z","updatedAt":"2018-01-01T00:00:05Z","deletedAt":null}],"_links":{"file":"/calls/12348765-4321-0987-6543-210987654321/legs/87654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789012.wav","self":"/calls/12345678-9012-3456-7890-123456789012/legs/12348765-4321-0987-6543-210987654321/recordings/12345678-9012-3456-7890-123456789012"},"pagination":{"totalCount":0,"pageCount":0,"currentPage":0,"perPage":0}}' - voice_recording = Client('', http_client).voice_recording_view('12348765-4321-0987-6543-210987654321', '87654321-0987-6543-2109-876543210987', '12345678-9012-3456-7890-123456789012') + voice_recording = Client('', http_client).voice_recording_view( + '12348765-4321-0987-6543-210987654321', + '87654321-0987-6543-2109-876543210987', + '12345678-9012-3456-7890-123456789012' + ) - http_client.request.assert_called_once_with('https://voice.messagebird.com/calls/12348765-4321-0987-6543-210987654321/legs/87654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789012', 'GET', None) + http_client.request.assert_called_once_with( + 'https://voice.messagebird.com/calls/12348765-4321-0987-6543-210987654321/legs/87654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789012', + 'GET', None) self.assertEqual('12345678-9012-3456-7890-123456789012', voice_recording.id) self.assertEqual('done', voice_recording.status) @@ -35,13 +41,24 @@ def test_voice_recording_list(self): http_client = Mock() http_client.request.return_value = '{"data":[{"id":"12345678-9012-3456-7890-123456789012","format":"wav","legId":"87654321-0987-6543-2109-876543210987","status":"done","duration":32,"type":"transfer","createdAt":"2018-01-01T00:00:01Z","updatedAt":"2018-01-01T00:00:05Z","deletedAt":null,"_links":{"file":"/calls/12348765-4321-0987-6543-210987654321/legs/7654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789012.wav","self":"/calls/12348765-4321-0987-6543-210987654321/legs/7654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789012"}},{"id":"12345678-9012-3456-7890-123456789013","format":"wav","legId":"87654321-0987-6543-2109-876543210987","status":"done","duration":12,"type":"transfer","createdAt":"2019-01-01T00:00:01Z","updatedAt":"2019-01-01T00:00:05Z","deletedAt":null,"_links":{"file":"/calls/12348765-4321-0987-6543-210987654321/legs/7654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789013.wav","self":"/calls/12348765-4321-0987-6543-210987654321/legs/7654321-0987-6543-2109-876543210987/recordings/12345678-9012-3456-7890-123456789013"}}],"_links":{"self":"/calls/12348765-4321-0987-6543-210987654321/legs/7654321-0987-6543-2109-876543210987/recordings?page=1"},"pagination":{"totalCount":2,"pageCount":1,"currentPage":1,"perPage":10}}' - voice_recordings = Client('', http_client).voice_recording_list_recordings('12348765-4321-0987-6543-210987654321', '87654321-0987-6543-2109-876543210987') + voice_recordings = Client('', http_client).voice_recording_list_recordings( + '12348765-4321-0987-6543-210987654321', '87654321-0987-6543-2109-876543210987') - http_client.request.assert_called_once_with('https://voice.messagebird.com/calls/12348765-4321-0987-6543-210987654321/legs/87654321-0987-6543-2109-876543210987/recordings', 'GET', None) + http_client.request.assert_called_once_with( + 'https://voice.messagebird.com/calls/12348765-4321-0987-6543-210987654321/legs/87654321-0987-6543-2109-876543210987/recordings', + 'GET', None) recordings_check = { - '12345678-9012-3456-7890-123456789012': { "id": '12345678-9012-3456-7890-123456789012', "duration": 32, "year": 2018 }, - '12345678-9012-3456-7890-123456789013': { "id": '12345678-9012-3456-7890-123456789013', "duration": 12, "year": 2019 } + '12345678-9012-3456-7890-123456789012': { + "id": '12345678-9012-3456-7890-123456789012', + "duration": 32, + "year": 2018 + }, + '12345678-9012-3456-7890-123456789013': { + "id": '12345678-9012-3456-7890-123456789013', + "duration": 12, + "year": 2019 + } } for item in voice_recordings._items: @@ -60,13 +77,16 @@ def test_voice_recording_download(self): http_client.request.return_value = '{"data":null,"errors":[{"message":"No recording found for ID `00000000-0000-0000-0000-000000000000`.","code":13}],"pagination":{"totalCount":0,"pageCount":0,"currentPage":0,"perPage":0}}' with self.assertRaises(ErrorException): - voice_recording = Client('', http_client).voice_recording_download('12348765-4321-0987-6543-210987654321', '87654321-0987-6543-2109-876543210987', '12345678-9012-3456-7890-123456789012') + voice_recording = Client('', http_client).voice_recording_download('12348765-4321-0987-6543-210987654321', + '87654321-0987-6543-2109-876543210987', + '12345678-9012-3456-7890-123456789012') http_client.request.return_value = '{"data":[{"id":"12345678-9012-3456-7890-123456789012","format":"wav","legId":"87654321-0987-6543-2109-876543210987","status":"done","duration":32,"type":"transfer","createdAt":"2018-01-01T00:00:01Z","updatedAt":"2018-01-01T00:00:05Z","deletedAt":null}],"pagination":{"totalCount":0,"pageCount":0,"currentPage":0,"perPage":0}}' with self.assertRaises(ErrorException): - voice_recording = Client('', http_client).voice_recording_download('12348765-4321-0987-6543-210987654321', '87654321-0987-6543-2109-876543210987', '12345678-9012-3456-7890-123456789012') - + voice_recording = Client('', http_client).voice_recording_download('12348765-4321-0987-6543-210987654321', + '87654321-0987-6543-2109-876543210987', + '12345678-9012-3456-7890-123456789012') if __name__ == '__main__': diff --git a/tests/test_voice_transcription.py b/tests/test_voice_transcription.py index 60f72b5..1383785 100644 --- a/tests/test_voice_transcription.py +++ b/tests/test_voice_transcription.py @@ -156,4 +156,4 @@ def test_download_voice_transcription(self): url + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '/transcriptions/' + transcription_id, 'GET', None - ) \ No newline at end of file + ) diff --git a/tests/test_voicemessage.py b/tests/test_voicemessage.py index c7f2a14..6130843 100644 --- a/tests/test_voicemessage.py +++ b/tests/test_voicemessage.py @@ -25,6 +25,14 @@ def test_voicemessage_create(self): http_client = Mock() http_client.request.return_value = '{}' - Client('', http_client).voice_message_create(['31612345678', '31687654321'], 'Hello World', { 'reference': 'MyReference' }) - - http_client.request.assert_called_once_with('voicemessages', 'POST', {'body': 'Hello World', 'recipients': '31612345678,31687654321', 'reference': 'MyReference'}) + Client('', http_client).voice_message_create( + ['31612345678', '31687654321'], + 'Hello World', + {'reference': 'MyReference'} + ) + + http_client.request.assert_called_once_with( + 'voicemessages', 'POST', + {'body': 'Hello World', 'recipients': '31612345678,31687654321', + 'reference': 'MyReference'} + ) From beb913079e40eb1feaf379f34e79b85e15249d3f Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Thu, 10 Oct 2019 13:07:05 +0200 Subject: [PATCH 21/24] Changed webhookId to a valid uuid in tests --- tests/test_voice_webhook.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_voice_webhook.py b/tests/test_voice_webhook.py index 6253acd..f2b16c3 100644 --- a/tests/test_voice_webhook.py +++ b/tests/test_voice_webhook.py @@ -109,6 +109,7 @@ def test_voice_create_webhook(self): "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" } }''' + create_webhook_request = VoiceCreateWebhookRequest(url="https://example.com/", title="FooBar", token="foobar") created_webhook = Client('', http_client).voice_create_webhook(create_webhook_request) @@ -152,7 +153,7 @@ def test_voice_update_webhook(self): "self": "/webhooks/534e1848-235f-482d-983d-e3e11a04f58a" } }''' - webhook_id = 'webhook-id' + webhook_id = '534e1848-235f-482d-983d-e3e11a04f58a' update_webhook_request = VoiceUpdateWebhookRequest(title="FooBar", token="foobar") updated_webhook = Client('', http_client).voice_update_webhook(webhook_id, update_webhook_request) @@ -164,7 +165,7 @@ def test_voice_update_webhook(self): def test_voice_delete_webhook(self): http_client = Mock() http_client.request.return_value = '' - webhook_id = 'webhook-id' + webhook_id = '534e1848-235f-482d-983d-e3e11a04f58a' Client('', http_client).voice_delete_webhook(webhook_id) http_client.request.assert_called_once_with( From d3fd626bc0ea0259ced34f15e7c8b2af9c7f2595 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Thu, 10 Oct 2019 13:08:45 +0200 Subject: [PATCH 22/24] New string formatting for example code --- examples/voice_create_webhook.py | 16 ++++++++-------- examples/voice_delete_webhook.py | 6 +++--- examples/voice_list_webhook.py | 17 +++++++++-------- examples/voice_read_webhook.py | 18 ++++++++++-------- examples/voice_update_webhook.py | 20 ++++++++++---------- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/examples/voice_create_webhook.py b/examples/voice_create_webhook.py index 2a5ed56..a9b017b 100644 --- a/examples/voice_create_webhook.py +++ b/examples/voice_create_webhook.py @@ -18,19 +18,19 @@ # Print the object information. print('\nThe following information was returned as a Voice Webhook object:\n') - print(' id : %s' % webhook.id) - print(' token : %s' % webhook.token) - print(' url : %s' % webhook.url) - print(' createdAtDatetime : %s' % webhook.createdDatetime) - print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + print(' id : {}'.format(webhook.id)) + print(' token : {}'.format(webhook.token)) + print(' url : {}'.format(webhook.url)) + print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) + print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) except messagebird.client.ErrorException as e: print('An error occured while creating a Voice Webhook object:') for error in e.errors: - print(' code : %d' % error.code) - print(' description : %s' % error.description) - print(' parameter : %s\n' % error.parameter) + print(' code : {}'.format(error.code)) + print(' description : {}'.format(error.description)) + print(' parameter : {}\n'.format(error.parameter)) diff --git a/examples/voice_delete_webhook.py b/examples/voice_delete_webhook.py index 89edf5d..dd09516 100644 --- a/examples/voice_delete_webhook.py +++ b/examples/voice_delete_webhook.py @@ -19,6 +19,6 @@ print('An error occured while deleting a Voice Webhook object:') for error in e.errors: - print(' code : %d' % error.code) - print(' description : %s' % error.description) - print(' parameter : %s\n' % error.parameter) + print(' code : {}'.format(error.code)) + print(' description : {}'.format(error.description)) + print(' parameter : {}\n'.format(error.parameter)) diff --git a/examples/voice_list_webhook.py b/examples/voice_list_webhook.py index 14a1cd7..1437306 100644 --- a/examples/voice_list_webhook.py +++ b/examples/voice_list_webhook.py @@ -16,21 +16,22 @@ if webhooks_list is None or webhooks_list.data is None: print("\nNo webhooks\n") exit(0) + # Print the object information. print('\nThe following information was returned as a Voice Webhook objects:\n') for webhook in webhooks_list.data: print('{') - print(' id : %s' % webhook.id) - print(' token : %s' % webhook.token) - print(' url : %s' % webhook.url) - print(' createdAtDatetime : %s' % webhook.createdDatetime) - print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + print(' id : {}'.format(webhook.id)) + print(' token : {}'.format(webhook.token)) + print(' url : {}'.format(webhook.url)) + print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) + print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) print('}\n') except messagebird.client.ErrorException as e: print('An error occured while reading a Voice Webhook object:') for error in e.errors: - print(' code : %d' % error.code) - print(' description : %s' % error.description) - print(' parameter : %s\n' % error.parameter) + print(' code : {}'.format(error.code)) + print(' description : {}'.format(error.description)) + print(' parameter : {}\n'.format(error.parameter)) diff --git a/examples/voice_read_webhook.py b/examples/voice_read_webhook.py index 2b12981..3c68691 100644 --- a/examples/voice_read_webhook.py +++ b/examples/voice_read_webhook.py @@ -16,16 +16,18 @@ # Print the object information. print('\nThe following information was returned as a Voice Webhook object:\n') - print(' id : %s' % webhook.id) - print(' token : %s' % webhook.token) - print(' url : %s' % webhook.url) - print(' createdAtDatetime : %s' % webhook.createdDatetime) - print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + + print(' id : {}'.format(webhook.id)) + print(' token : {}'.format(webhook.token)) + print(' url : {}'.format(webhook.url)) + print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) + print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) + except messagebird.client.ErrorException as e: print('An error occured while reading a Voice Webhook object:') for error in e.errors: - print(' code : %d' % error.code) - print(' description : %s' % error.description) - print(' parameter : %s\n' % error.parameter) + print(' code : {}'.format(error.code)) + print(' description : {}'.format(error.description)) + print(' parameter : {}\n'.format(error.parameter)) diff --git a/examples/voice_update_webhook.py b/examples/voice_update_webhook.py index f73c404..f3fac7e 100644 --- a/examples/voice_update_webhook.py +++ b/examples/voice_update_webhook.py @@ -14,24 +14,24 @@ try: client = messagebird.Client(args['accessKey']) - create_webhook_request = VoiceUpdateWebhookRequest(title=args['title'], token=args['token']) - webhook = client.voice_update_webhook(args['webhookId'], create_webhook_request) + update_webhook_request = VoiceUpdateWebhookRequest(title=args['title'], token=args['token']) + webhook = client.voice_update_webhook(args['webhookId'], update_webhook_request) # Print the object information. print('\nThe following information was returned as a Voice Webhook object:\n') - print(' id : %s' % webhook.id) - print(' token : %s' % webhook.token) - print(' url : %s' % webhook.url) - print(' createdAtDatetime : %s' % webhook.createdDatetime) - print(' updatedAtDatetime : %s' % webhook.updatedDatetime) + print(' id : {}'.format(webhook.id)) + print(' token : {}'.format(webhook.token)) + print(' url : {}'.format(webhook.url)) + print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) + print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) except messagebird.client.ErrorException as e: print('An error occured while updating a Voice Webhook object:') for error in e.errors: - print(' code : %d' % error.code) - print(' description : %s' % error.description) - print(' parameter : %s\n' % error.parameter) + print(' code : {}'.format(error.code)) + print(' description : {}'.format(error.description)) + print(' parameter : {}\n'.format(error.parameter)) From 19b02dd5cd56ed6fcbdf7f0148375b58d130cd89 Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Thu, 10 Oct 2019 13:24:33 +0200 Subject: [PATCH 23/24] Fixes in tests and voice webhook class for consistency --- examples/voice_create_webhook.py | 4 ++-- examples/voice_list_webhook.py | 4 ++-- examples/voice_read_webhook.py | 4 ++-- examples/voice_update_webhook.py | 4 ++-- messagebird/error.py | 7 +------ messagebird/voice_webhook.py | 24 ++++++++++++------------ 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/examples/voice_create_webhook.py b/examples/voice_create_webhook.py index a9b017b..a8785ee 100644 --- a/examples/voice_create_webhook.py +++ b/examples/voice_create_webhook.py @@ -21,8 +21,8 @@ print(' id : {}'.format(webhook.id)) print(' token : {}'.format(webhook.token)) print(' url : {}'.format(webhook.url)) - print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) - print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) + print(' createdAt : {}'.format(webhook.createdAt)) + print(' updatedAt : {}'.format(webhook.updatedAt)) except messagebird.client.ErrorException as e: print('An error occured while creating a Voice Webhook object:') diff --git a/examples/voice_list_webhook.py b/examples/voice_list_webhook.py index 1437306..4df4b2f 100644 --- a/examples/voice_list_webhook.py +++ b/examples/voice_list_webhook.py @@ -24,8 +24,8 @@ print(' id : {}'.format(webhook.id)) print(' token : {}'.format(webhook.token)) print(' url : {}'.format(webhook.url)) - print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) - print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) + print(' createdAt : {}'.format(webhook.createdAt)) + print(' updatedAt : {}'.format(webhook.updatedAt)) print('}\n') except messagebird.client.ErrorException as e: diff --git a/examples/voice_read_webhook.py b/examples/voice_read_webhook.py index 3c68691..b5b08de 100644 --- a/examples/voice_read_webhook.py +++ b/examples/voice_read_webhook.py @@ -20,8 +20,8 @@ print(' id : {}'.format(webhook.id)) print(' token : {}'.format(webhook.token)) print(' url : {}'.format(webhook.url)) - print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) - print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) + print(' createdAt : {}'.format(webhook.createdAt)) + print(' updatedAt : {}'.format(webhook.updatedAt)) except messagebird.client.ErrorException as e: diff --git a/examples/voice_update_webhook.py b/examples/voice_update_webhook.py index f3fac7e..7982ef9 100644 --- a/examples/voice_update_webhook.py +++ b/examples/voice_update_webhook.py @@ -22,8 +22,8 @@ print(' id : {}'.format(webhook.id)) print(' token : {}'.format(webhook.token)) print(' url : {}'.format(webhook.url)) - print(' createdAtDatetime : {}'.format(webhook.createdDatetime)) - print(' updatedAtDatetime : {}'.format(webhook.updatedDatetime)) + print(' createdAt : {}'.format(webhook.createdAt)) + print(' updatedAt : {}'.format(webhook.updatedAt)) except messagebird.client.ErrorException as e: print('An error occured while updating a Voice Webhook object:') diff --git a/messagebird/error.py b/messagebird/error.py index 46abe18..e086491 100644 --- a/messagebird/error.py +++ b/messagebird/error.py @@ -11,12 +11,7 @@ def __str__(self): return str(dict(code=self.code, description=self.description, parameter=self.parameter)) -class BaseError(Exception): - """Base class for exceptions in this module.""" - pass - - -class ValidationError(BaseError): +class ValidationError(ValueError): """Exception raised for errors in validation. Attributes: diff --git a/messagebird/voice_webhook.py b/messagebird/voice_webhook.py index e4cac69..7d752b7 100644 --- a/messagebird/voice_webhook.py +++ b/messagebird/voice_webhook.py @@ -7,27 +7,27 @@ def __init__(self): self.id = None self.url = None self.token = None - self._createdDatetime = None - self._updatedDatetime = None + self._createdAtDatetime = None + self._updatedAtDatetime = None self._links = None @property - def createdDatetime(self): - return self._createdDatetime + def createdAtDatetime(self): + return self._createdAtDatetime - @createdDatetime.setter + @createdAtDatetime.setter def createdAt(self, value): if value is not None: - self._createdDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') + self._createdAtDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') @property - def updatedDatetime(self): - return self._updatedDatetime + def updatedAtDatetime(self): + return self._updatedAtDatetime - @updatedDatetime.setter + @updatedAtDatetime.setter def updatedAt(self, value): if value is not None: - self._updatedDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') + self._updatedAtDatetime = self.value_to_time(value, '%Y-%m-%dT%H:%M:%SZ') def load(self, data): if data.get('data') is not None: @@ -46,8 +46,8 @@ def __str__(self): 'webhook id : %s' % self.id, 'url : %s' % self.url, 'token : %s' % self.token, - 'created date time : %s' % self._createdDatetime, - 'updated date time : %s' % self._updatedDatetime, + 'createdAtDatetime : %s' % self._createdAtDatetime, + 'updatedAtDatetime : %s' % self._updatedAtDatetime, 'links : %s' % self._links ]) From 352fc05f5e299533d311937a8d8a089bd005920b Mon Sep 17 00:00:00 2001 From: "morsesfeeler@live.ru" Date: Thu, 10 Oct 2019 13:58:14 +0200 Subject: [PATCH 24/24] Changed allowed methods check --- messagebird/http_client.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/messagebird/http_client.py b/messagebird/http_client.py index c25148f..4dcf1e9 100644 --- a/messagebird/http_client.py +++ b/messagebird/http_client.py @@ -43,10 +43,10 @@ def request(self, path, method='GET', params=None, format=ResponseFormat.text): 'POST': lambda: requests.post(url, verify=True, headers=headers, data=json_serialize(params)), 'PUT': lambda: requests.put(url, verify=True, headers=headers, data=json_serialize(params)) } - response = method_switcher.get(method, str(method) + ' is not a supported HTTP method') - if isinstance(response, str): - raise ValueError(response) - response = response() + if method not in method_switcher: + raise ValueError(str(method) + ' is not a supported HTTP method') + + response = method_switcher[method]() if response.status_code not in self.__supported_status_codes: response.raise_for_status()