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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@ target/

# PyCharm
.idea/

# pyvenv
venv/
48 changes: 48 additions & 0 deletions examples/call_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python
import os
import sys
import json
import argparse
import requests

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import messagebird

parser = argparse.ArgumentParser(usage='call_create.py\
--accessKey="*******" \
--callId=dda20377-72da-4846-9b2c-0fea3ad4bcb6 \
')
parser.add_argument('--accessKey', help='Access key for MessageBird API.', type=str, required=True)
parser.add_argument('--callId', help='The ID of the MessageBird call to delete.', type=str, required=True)
args = vars(parser.parse_args())

try:
# Create a MessageBird client with the specified accessKey.
client = messagebird.Client(args['accessKey'])

# Create a call for the specified callID.
call = client.call_delete(args['callId'])

# If no error is thrown, means delete was successful.
print('\nDeleted call with id `%s` successfully!' % args['callId'])

except messagebird.client.ErrorException as e:
print('\nAn error occurred while creating a call:\n')

for error in e.errors:
print(' code : %d' % error.code)
print(' description : %s' % error.description)
print(' parameter : %s' % error.parameter)
print(' type : %s' % error.__class__)

except requests.exceptions.HTTPError as e:
print('\nAn http exception occurred while deleting a call:')
print(' ', e)
print(' Http request body: ', e.request.body)
print(' Http response status: ', e.response.status_code)
print(' Http response body: ', e.response.content.decode())

except Exception as e:
print('\nAn ', e.__class__, ' exception occurred while deleting a call:')
print(e)

64 changes: 64 additions & 0 deletions examples/call_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python
import os
import sys
import argparse
import requests

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import messagebird


parser = argparse.ArgumentParser(usage='call_create.py\
--accessKey="*******" \
--page=1 \
')
parser.add_argument('--accessKey', help='Access key for MessageBird API.', type=str, required=True)
parser.add_argument('--page', help='The page you wish to view.', type=str, required=False, default=1)
args = vars(parser.parse_args())

try:
# Create a MessageBird client with the specified accessKey.
client = messagebird.Client(args['accessKey'])
del(args['accessKey'])

# Create a call for the specified callID.
callList = client.call_list(**args)

# Print the object information.
print('\nThe following information was returned as a %s object:\n' % callList.__class__)
if callList.items is not None:
print(' Containing the the following items:')
for item in callList.items:
print(' {')
print(' id : %s' % item.id)
print(' status : %s' % item.status)
print(' source : %s' % item.source)
print(' destination : %s' % item.destination)
print(' createdAt : %s' % item.createdAt)
print(' updatedAt : %s' % item.updatedAt)
print(' endedAt : %s' % item.endedAt)
print(' },')
else:
print(' With an empty response.')

except messagebird.client.ErrorException as e:
print('\nAn error occurred while listing calls:\n')

for error in e.errors:
print(' code : %d' % error.code)
print(' description : %s' % error.description)
print(' parameter : %s' % error.parameter)
print(' type : %s' % error.__class__)

except requests.exceptions.HTTPError as e:
print('\nAn HTTP exception occurred while listing calls:')
print(' ', e)
print(' Http request body: ', e.request.body)
print(' Http response status: ', e.response.status_code)
print(' Http response body: ', e.response.content.decode())

except Exception as e:
print('\nAn ', e.__class__, ' exception occurred while creating a call:')
print(e)


4 changes: 4 additions & 0 deletions messagebird/base_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ def items(self, value):
items.append(self.itemType().load(item))

self._items = items

def __str__(self):
items_count = 0 if self.items is None else len(self.items)
return str(self.__class__) + " with %d items.\n" % items_count

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return "%s with %d items.\n" % (str(self.__class__), items_count) would be a bit nicer

42 changes: 42 additions & 0 deletions messagebird/call_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from messagebird.base_list import BaseList
from messagebird.call_data import CallData


class CallList(BaseList):
def __init__(self):
# We're expecting items of type CallData
super(CallList, self).__init__(CallData)
self.perPage = None
self.currentPage = None
self.pageCount = None
self._pagination = None

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

@property
def pagination(self):
return {
"totalCount": self.totalCount,
"pageCount": self.pageCount,
"currentPage": self.currentPage,
"perPage": self.perPage
}

@pagination.setter
def pagination(self, value):
if isinstance(value, dict):
self.totalCount = value['totalCount']
self.pageCount = value['pageCount']
self.currentPage = value['currentPage']
self.perPage = value['perPage']
self.limit = self.perPage * self.currentPage
self.offset = self.perPage * (self.currentPage - 1)

@data.setter
def data(self, value):
if isinstance(value, list):
self.count = len(value)
self.items = value

30 changes: 27 additions & 3 deletions messagebird/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from messagebird.balance import Balance
from messagebird.call import Call
from messagebird.call_list import CallList
from messagebird.contact import Contact, ContactList
from messagebird.error import Error
from messagebird.group import Group, GroupList
Expand Down Expand Up @@ -50,6 +51,10 @@ 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

Expand Down Expand Up @@ -124,6 +129,18 @@ def call(self,id):
"""Retrieve the information of a specific call"""
return Call().load(self.request('calls/' + str(id), 'GET', None, VOICE_TYPE))

def call_list(self, page=1):
"""Listing calls

Args:
page(int) : The page to list.
Raises:
ErrorException : On api returning errors

Returns:
CallList(object) : The list of calls requested & their status."""
return CallList().load(self.request('calls/?page=' + str(page), 'GET', None, VOICE_TYPE))

def call_create(self, source, destination, callFlow, webhook):
"""Creating a call

Expand All @@ -133,16 +150,23 @@ def call_create(self, source, destination, callFlow, webhook):
callFlow(object) : The call flow object to be executed when the call is answered.
webhook(object) : The webhook object containing the url & required token.
Raises:
ErrorException: On api returning errors
ErrorException : On api returning errors

Returns:
If successful, this request will return an object with a data property, which is an array that has a single
call object. If the request failed, an error object will be returned."""
Call(object) : The Call object just created."""

params = locals()
del(params['self'])
return Call().load(self.request('calls', 'POST', params, VOICE_TYPE))

def call_delete(self, id):
"""Delete an existing call object."""
response = self.request_plain_text('calls/' + str(id), 'DELETE', None, VOICE_TYPE)

# successful delete should be empty
if len(response) > 0:
raise SignleErrorException(response)

def hlr(self, id):
"""Retrieve the information of a specific HLR lookup."""
return HLR().load(self.request('hlr/' + str(id)))
Expand Down
83 changes: 72 additions & 11 deletions tests/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest
from messagebird import Client, ErrorException
from messagebird.base import Base
from messagebird.client import VOICE_TYPE

try:
from unittest.mock import Mock
Expand Down Expand Up @@ -47,6 +48,68 @@ def test_call(self):

self.assertEqual('ended', call.data.status)

def test_call_list(self):
http_client = Mock()
http_client.request.return_value = """
{
"data":[
{
"id":"dda20377-72da-4846-9b2c-0fea3ad4bcb6",
"status":"no_answer",
"source":"16479311111",
"destination":"1416555555",
"createdAt":"2019-08-06T13:17:06Z",
"updatedAt":"2019-08-06T13:17:39Z",
"endedAt":"2019-08-06T13:17:39Z",
"_links":{
"legs":"/calls/dda20377-72da-4846-9b2c-0fea3ad4bcb6/legs",
"self":"/calls/dda20377-72da-4846-9b2c-0fea3ad4bcb6"
}
},
{
"id":"1541535b-9b80-4002-bde5-ed05b5ebed76",
"status":"ended",
"source":"16479311111",
"destination":"1416555556",
"createdAt":"2019-08-06T13:17:06Z",
"updatedAt":"2019-08-06T13:17:39Z",
"endedAt":"2019-08-06T13:17:39Z",
"_links":{
"legs":"/calls/1541535b-9b80-4002-bde5-ed05b5ebed76/legs",
"self":"/calls/1541535b-9b80-4002-bde5-ed05b5ebed76"
}
}
],
"_links": {
"self": "/calls?page=1"
},
"pagination":{
"totalCount":2,
"pageCount":1,
"currentPage":1,
"perPage":10
}
}
"""

callList = Client('', http_client).call_list(page=1)

http_client.request.assert_called_once_with('calls/?page=1', 'GET', None)

# check data is processed
self.assertEqual('no_answer', callList.data[0].status)
self.assertEqual('ended', callList.data[1].status)

# check pagination is passed to object
self.assertEqual(2, callList.totalCount)
self.assertEqual(1, callList.pageCount)
self.assertEqual(1, callList.currentPage)
self.assertEqual(10, callList.perPage)
self.assertEqual(10, callList.pagination['perPage'], 'Check it also supports API pagination format.')

self.assertEqual(0, callList.offset, 'Check it correctly calculates offset.')
self.assertEqual(10, callList.limit, 'Check it correctly calculates limit.')

def test_call_create(self):
api_response = {
"data": [
Expand Down Expand Up @@ -100,17 +163,15 @@ def test_call_create(self):
self.assertEqual(expected_data, response_data, 'Check client response contains the API response data.')

# check it can be formatted as string
expected_call_string = 'id : None\n' + \
'data.id : 21025ed1-cc1d-4554-ac05-043fa6c84e00\n' + \
'data.status : queued\n' + \
'data.source : 31644556677\n' + \
'data.destination : 31612345678\n' + \
'data.webhook : None\n' + \
'data.updatedAt : 2017-08-30 07:35:37+00:00\n' + \
'data.createdAt : 2017-08-30 07:35:37+00:00\n' + \
'data.endedAt : None'
self.assertEqual(expected_call_string, str(call_creation_response), 'Check returned call can be formatted as' +
' string')
self.assertTrue(len(str(call_creation_response)) > 0, 'Check returned call can be formatted as string.')

def test_call_delete(self):
http_client = Mock()
http_client.request.return_value = ''
call_id_to_delete = '21025ed1-cc1d-4554-ac05-043fa6c84e00'
Client('', http_client).call_delete(call_id_to_delete)

http_client.request.assert_called_once_with('calls/%s' % call_id_to_delete, 'DELETE', None)

@staticmethod
def create_expected_call_data_based_on_api_response(api_response):
Expand Down