Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions examples/call_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python

import sys
import messagebird

#ACCESS_KEY = ''
#CALL_FLOW_ID = ''

try:
ACCESS_KEY
except NameError:
print('You need to set an ACCESS_KEY constant in this file')
sys.exit(1)

try:
CALL_FLOW_ID
except NameError:
print('You need to set a CALL_FLOW_ID constant in this file')
sys.exit(1)

try:
# Create a MessageBird client with the specified ACCESS_KEY.
client = messagebird.Client(ACCESS_KEY)

# Fetch the CallFlow object for the specified CALL_FLOW_ID.
call = client.call_flow(CALL_FLOW_ID)

# Print the object information.
print('\nThe following information was returned as a CallFlow object:\n')
print(' id : {}'.format(call.id))
print(' title : {}'.format(call.title))
print(' steps : ')
for step in call.steps:
print(step)

print(' record : {}'.format(call.record))
print(' default : {}'.format(call.default))
print(' updatedAt : {}'.format(call.updatedAt))
print(' createdAt : {}'.format(call.createdAt))

except messagebird.client.ErrorException as e:
print('\nAn error occured while requesting a CallFlow object:\n')

for error in e.errors:
print(' code : {}'.format(error.code))
print(' description : {}'.format(error.description))
print(' parameter : {}\n'.format(error.parameter))
137 changes: 137 additions & 0 deletions messagebird/call_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from messagebird.base import Base
from messagebird.base_list import BaseList


class CallFlowList(BaseList):

def __init__(self):
self._data = None
self._pagination = None

super(CallFlowList, self).__init__(CallFlow)

@property
def data(self):
return self._data

@property
def pagination(self):
return self._pagination

@pagination.setter
def pagination(self, value):
self._pagination = value

@data.setter
def data(self, value):
"""Create typed objects from the dicts."""
items = []
for item in value:
items.append(self.itemType().load(item))

self._data = items


class CallFlowNumberList(BaseList):
def __init__(self):
self._data = None
self._pagination = None

super(CallFlowNumberList, self).__init__(CallFlowNumber)

@property
def data(self):
return self._data

@property
def pagination(self):
return self._pagination

@pagination.setter
def pagination(self, value):
self._pagination = value

@data.setter
def data(self, value):
"""Create typed objects from the dicts."""
items = []
for item in value:
items.append(self.itemType().load(item))

self._data = items

class CallFlow(Base):

def __init__(self):
self.id = None
self.title = None
self.record = None
self.steps = None
self.default = None
self._createdAt = None
self._updatedAt = None

@property
def createdAt(self):
return self._createdAt

@createdAt.setter
def createdAt(self, value):
self._createdAt = self.value_to_time(value)

@property
def updatedAt(self):
return self._updatedAt

@updatedAt.setter
def updatedAt(self, value):
self._updatedAt = self.value_to_time(value)

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


class CallFlowNumber(Base):
def __init__(self):
self.id = None
self.number = None
self.callFlowId = None
self._createdAt = None
self._updatedAt = None

@property
def createdAt(self):
return self._createdAt

@createdAt.setter
def createdAt(self, value):
self._createdAt = self.value_to_time(value)

@property
def updatedAt(self):
return self._updatedAt

@updatedAt.setter
def updatedAt(self, value):
self._updatedAt = self.value_to_time(value)

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
30 changes: 28 additions & 2 deletions messagebird/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from messagebird.conversation import Conversation, ConversationList
from messagebird.conversation_webhook import ConversationWebhook, ConversationWebhookList
from messagebird.voice_recording import VoiceRecordingsList, VoiceRecording
from messagebird.call_flow import CallFlow, CallFlowList, CallFlowNumberList


ENDPOINT = 'https://rest.messagebird.com'
Expand Down Expand Up @@ -58,7 +59,7 @@ class Client(object):
def __init__(self, access_key, http_client=None, features=[]):
self.access_key = access_key
self.http_client = http_client

self.conversation_api_root = CONVERSATION_API_WHATSAPP_SANDBOX_ROOT if Feature.ENABLE_CONVERSATIONS_API_WHATSAPP_SANDBOX in features else CONVERSATION_API_ROOT

def _get_http_client(self, type=REST_TYPE):
Expand All @@ -67,7 +68,7 @@ def _get_http_client(self, type=REST_TYPE):

if type == CONVERSATION_TYPE:
return HttpClient(self.conversation_api_root, self.access_key, USER_AGENT)

if type == VOICE_TYPE:
return HttpClient(VOICE_API_ROOT, self.access_key, USER_AGENT)

Expand Down Expand Up @@ -356,5 +357,30 @@ 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 call_flow(self, id):
return CallFlow().load(self.request('call-flows/' + str(id), 'GET', None, VOICE_TYPE))

def call_flow_list(self, limit=10, offset=0):
query = self._format_query(limit, offset)
return CallFlowList().load(self.request('call-flows?' + query, 'GET', None, VOICE_TYPE))

def call_flow_create(self, title, steps, default=False, record=False):
params = {'title': title, 'steps': steps, 'default': default, 'record': record}
return CallFlow().load(self.request('call-flows', 'POST', params, VOICE_TYPE))

def call_flow_update(self, id, title, steps, default, record):
params = {'title': title, 'steps': steps, 'default': default, 'record': record}
return CallFlow().load(self.request('call-flows/' + str(id), 'PUT', params, VOICE_TYPE))

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))

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))

def _format_query(self, limit, offset):
return 'limit=' + str(limit) + '&offset=' + str(offset)
152 changes: 152 additions & 0 deletions tests/test_call_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import unittest
from messagebird import Client

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 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"
}
}
],
"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')
http_client.request.assert_called_once_with('call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635', 'GET', None)

self.assertEqual('Updated call flow', call_flow.title)
self.assertIsNotNone(call_flow.steps)

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"
}
}
],
"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)

http_client.request.assert_called_once_with('call-flows?limit=20&offset=0', 'GET', None)

self.assertEqual('Forward call to 0600123123', call_flow_list.data[1].title)
self.assertEqual(2, call_flow_list.pagination['totalCount'])

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
}
}
'''

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)

self.assertEqual('31611111111', number_list.data[0].number)
self.assertEqual(1, number_list.pagination['totalCount'])

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'])

params = {'numbers': ['31611111111', '31611111112']}

http_client.request.assert_called_once_with('call-flows/de3ed163-d5fc-45f4-b8c4-7eea7458c635/numbers', 'POST', params)