Skip to content

Commit d150161

Browse files
authored
Merge pull request #20 from messagebird/add-contacts
Add contacts
2 parents a77b7c1 + e0e8278 commit d150161

File tree

5 files changed

+241
-1
lines changed

5 files changed

+241
-1
lines changed

messagebird/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from messagebird.client import Client
1+
from messagebird.client import Client, ErrorException

messagebird/base_list.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from messagebird.base import Base
2+
3+
4+
class Links(Base):
5+
6+
def __init__(self):
7+
self.first = None
8+
self.previous = None
9+
self.next = None
10+
self.last = None
11+
12+
13+
class BaseList(Base):
14+
15+
def __init__(self, item_type):
16+
"""When setting items, they are instantiated as objects of type item_type."""
17+
self.limit = None
18+
self.offset = None
19+
self.count = None
20+
self.totalCount = None
21+
self._links = None
22+
self._items = None
23+
24+
self.itemType = item_type
25+
26+
@property
27+
def links(self):
28+
return self._links
29+
30+
@links.setter
31+
def links(self, value):
32+
self._links = Links().load(value)
33+
34+
@property
35+
def items(self):
36+
return self._items
37+
38+
@items.setter
39+
def items(self, value):
40+
"""Create typed objects from the dicts."""
41+
items = []
42+
for item in value:
43+
items.append(self.itemType().load(item))
44+
45+
self._items = items

messagebird/client.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from messagebird.base import Base
55
from messagebird.balance import Balance
6+
from messagebird.contact import Contact, ContactList
67
from messagebird.error import Error
78
from messagebird.hlr import HLR
89
from messagebird.http_client import HttpClient
@@ -43,6 +44,24 @@ def request(self, path, method='GET', params=None):
4344

4445
return response_json
4546

47+
def request_plain_text(self, path, method='GET', params=None):
48+
"""Builds a request, gets a response and returns the body."""
49+
response_text = self.http_client.request(path, method, params)
50+
51+
try:
52+
# Try to decode the response to JSON to see if the API returned any
53+
# errors.
54+
response_json = json.loads(response_text)
55+
56+
if 'errors' in response_json:
57+
raise (ErrorException([Error().load(e) for e in response_json['errors']]))
58+
except ValueError:
59+
# Do nothing: json.loads throws if the input string is not valid JSON,
60+
# which is expected. We'll just return the response body below.
61+
pass
62+
63+
return response_text
64+
4665
def balance(self):
4766
"""Retrieve your balance."""
4867
return Balance().load(self.request('balance'))
@@ -109,3 +128,22 @@ def verify_create(self, recipient, params=None):
109128
def verify_verify(self, id, token):
110129
"""Verify the token of a specific verification."""
111130
return Verify().load(self.request('verify/' + str(id), params={'token': token}))
131+
132+
def contact(self, id):
133+
"""Retrieve the information of a specific contact."""
134+
return Contact().load(self.request('contacts/' + str(id)))
135+
136+
def contact_create(self, phonenumber, params=None):
137+
if params is None: params = {}
138+
params.update({'msisdn': phonenumber})
139+
return Contact().load(self.request('contacts', 'POST', params))
140+
141+
def contact_delete(self, id):
142+
self.request_plain_text('contacts/' + str(id), 'DELETE')
143+
144+
def contact_update(self, id, params=None):
145+
self.request_plain_text('contacts/' + str(id), 'PATCH', params)
146+
147+
def contact_list(self, limit=0, offset=0):
148+
query = 'limit='+str(limit)+'&offset='+str(offset)
149+
return ContactList().load(self.request('contacts?'+query, 'GET', None))

messagebird/contact.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from messagebird.base import Base
2+
from messagebird.base_list import BaseList
3+
4+
5+
class CustomDetails(Base):
6+
7+
def __init__(self):
8+
self.custom1 = None
9+
self.custom2 = None
10+
self.custom3 = None
11+
self.custom4 = None
12+
13+
14+
class GroupReference(Base):
15+
16+
def __init__(self):
17+
self.href = None
18+
self.totalCount = None
19+
20+
21+
class MessageReference(Base):
22+
23+
def __init__(self):
24+
self.href = None
25+
self.totalCount = None
26+
27+
28+
class ContactList(BaseList):
29+
30+
def __init__(self):
31+
# Signal the BaseList that we're expecting items of type Contact...
32+
super(ContactList, self).__init__(Contact)
33+
34+
35+
class Contact(Base):
36+
37+
def __init__(self):
38+
self.id = None
39+
self.href = None
40+
self.msisdn = None
41+
self.firstName = None
42+
self.lastName = None
43+
self._customDetails = None
44+
self._groups = None
45+
self._messages = None
46+
self._createdDatetime = None
47+
self._updatedDatetime = None
48+
49+
@property
50+
def customDetails(self):
51+
return self._customDetails
52+
53+
@customDetails.setter
54+
def customDetails(self, value):
55+
self._customDetails = CustomDetails().load(value)
56+
57+
@property
58+
def groups(self):
59+
return self._groups
60+
61+
@groups.setter
62+
def groups(self, value):
63+
self._groups = GroupReference().load(value)
64+
65+
@property
66+
def messages(self):
67+
return self._messages
68+
69+
@messages.setter
70+
def messages(self, value):
71+
self._messages = MessageReference().load(value)
72+
73+
@property
74+
def createdDatetime(self):
75+
return self._createdDatetime
76+
77+
@createdDatetime.setter
78+
def createdDatetime(self, value):
79+
self._createdDatetime = self.value_to_time(value)
80+
81+
@property
82+
def updatedDatetime(self):
83+
return self._updatedDatetime
84+
85+
@updatedDatetime.setter
86+
def updatedDatetime(self, value):
87+
self._updatedDatetime = self.value_to_time(value)

tests/test_contact.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import unittest
2+
from messagebird import Client, ErrorException
3+
4+
try:
5+
from unittest.mock import Mock
6+
except ImportError:
7+
# mock was added to unittest in Python 3.3, but was an external library
8+
# before.
9+
from mock import Mock
10+
11+
12+
class TestContact(unittest.TestCase):
13+
14+
def test_contact(self):
15+
http_client = Mock()
16+
http_client.request.return_value = '{"id": "contact-id","href": "https://rest.messagebird.com/contacts/contact-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","customDetails": {"custom1": "First","custom2": "Second","custom3": "Third","custom4": "Fourth"},"groups": {"totalCount": 3,"href": "https://rest.messagebird.com/contacts/contact-id/groups"},"messages": {"totalCount": 5,"href": "https://rest.messagebird.com/contacts/contact-id/messages"},"createdDatetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:44:08+00:00"}'
17+
18+
contact = Client('', http_client).contact('contact-id')
19+
20+
http_client.request.assert_called_once_with('contacts/contact-id', 'GET', None)
21+
22+
self.assertEqual(31612345678, contact.msisdn)
23+
self.assertEqual('First', contact.customDetails.custom1)
24+
self.assertEqual(3, contact.groups.totalCount)
25+
self.assertEqual('https://rest.messagebird.com/contacts/contact-id/messages', contact.messages.href)
26+
27+
def test_contact_create(self):
28+
http_client = Mock()
29+
http_client.request.return_value = '{}'
30+
31+
Client('', http_client).contact_create(31612345678, {'firstName': 'Foo', 'custom3': 'Third'})
32+
33+
http_client.request.assert_called_once_with('contacts', 'POST', {'msisdn': 31612345678, 'firstName': 'Foo', 'custom3': 'Third'})
34+
35+
def test_contact_delete(self):
36+
http_client = Mock()
37+
http_client.request.return_value = ''
38+
39+
Client('', http_client).contact_delete('contact-id')
40+
41+
http_client.request.assert_called_once_with('contacts/contact-id', 'DELETE', None)
42+
43+
def test_contact_delete_invalid(self):
44+
http_client = Mock()
45+
http_client.request.return_value = '{"errors": [{"code": 20,"description": "contact not found","parameter": null}]}'
46+
47+
with self.assertRaises(ErrorException):
48+
Client('', http_client).contact_delete('non-existent-contact-id')
49+
50+
http_client.request.assert_called_once_with('contacts/non-existent-contact-id', 'DELETE', None)
51+
52+
def test_contact_update(self):
53+
http_client = Mock()
54+
http_client.request.return_value = ''
55+
56+
Client('', http_client).contact_update('contact-id', {'msisdn': 31687654321, 'custom4': 'fourth'})
57+
58+
http_client.request.assert_called_once_with('contacts/contact-id', 'PATCH', {'msisdn': 31687654321, 'custom4': 'fourth'})
59+
60+
def test_contact_list(self):
61+
http_client = Mock()
62+
http_client.request.return_value = '{"offset": 0,"limit": 20,"count": 2,"totalCount": 2,"links": {"first": "https://rest.messagebird.com/contacts?offset=0","previous": null,"next": null,"last": "https://rest.messagebird.com/contacts?offset=0"},"items": [{"id": "first-id","href": "https://rest.messagebird.com/contacts/first-id","msisdn": 31612345678,"firstName": "Foo","lastName": "Bar","customDetails": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/first-id/messages"},"createdDatetime": "2018-07-13T10:34:08+00:00","updatedDatetime": "2018-07-13T10:34:08+00:00"},{"id": "second-id","href": "https://rest.messagebird.com/contacts/second-id","msisdn": 49612345678,"firstName": "Hello","lastName": "World","customDetails": {"custom1": null,"custom2": null,"custom3": null,"custom4": null},"groups": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/groups"},"messages": {"totalCount": 0,"href": "https://rest.messagebird.com/contacts/second-id/messages"},"createdDatetime": "2018-07-13T10:33:52+00:00","updatedDatetime": null}]}'
63+
64+
contact_list = Client('', http_client).contact_list(10, 20)
65+
66+
http_client.request.assert_called_once_with('contacts?limit=10&offset=20', 'GET', None)
67+
68+
self.assertEqual(2, contact_list.totalCount)
69+
self.assertEqual('https://rest.messagebird.com/contacts?offset=0', contact_list.links.first)
70+
self.assertEqual('https://rest.messagebird.com/contacts/first-id/groups', contact_list.items[0].groups.href)

0 commit comments

Comments
 (0)