-
Notifications
You must be signed in to change notification settings - Fork 8
/
__init__.py
executable file
·213 lines (168 loc) · 6.71 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import json
import re
import platform
import requests
from .exception import ClickatellError
class Transport:
"""
Abstract representation of a transport class. Defines
the supported API methods
"""
endpoint = "api.clickatell.com"
status = {
"001": "The message ID is incorrect or reporting is delayed.",
"002": "The message could not be delivered and has been queued for attempted redelivery.",
"003": "Delivered to the upstream gateway or network (delivered to the recipient).",
"004": "Confirmation of receipt on the handset of the recipient.",
"005": "There was an error with the message, probably caused by the content of the message itself.",
"006": "The message was terminated by a user (stop message command) or by our staff.",
"007": "An error occurred delivering the message to the handset. 008 0x008 OK Message received by gateway.",
"009": "The routing gateway or network has had an error routing the message.",
"010": "Message has expired before we were able to deliver it to the upstream gateway. No charge applies.",
"011": "Message has been queued at the gateway for delivery at a later time (delayed delivery).",
"012": "The message cannot be delivered due to a lack of funds in your account. Please re-purchase credits.",
"014": "Maximum MT limit exceeded The allowable amount for MT messaging has been exceeded."
}
def __init__(self, secure=False):
"""
Construct a new transportation instance.
:param boolean secure: Should we try and use a secure connection
"""
self.secure = secure
pass
def merge(self, *args):
"""
Merge multiple dictionary objects into one.
:param variadic args: Multiple dictionary items
:return dict
"""
values = []
for entry in args:
values = values + list(entry.items())
return dict(values)
def parseLegacy(self, response):
"""
Parse a legacy response and try and catch any errors. If we have multiple
responses we wont catch any exceptions, we will return the errors
row by row
:param dict response: The response string returned from request()
:return Returns a dictionary or a list (list for multiple responses)
"""
lines = response.splitlines()
result = []
pattern = re.compile('([A-Za-z]+):((.(?![A-Za-z]+:))*)')
for line in lines:
matches = pattern.findall(line)
row = {}
for match in matches:
row[match[0]] = match[1].strip()
try:
error = row['ERR'].split(',')
except KeyError:
pass
else:
row['code'] = error[0] if len(error) == 2 else 0
row['error'] = error[1].strip() if len(error) == 2 else error[0]
del row['ERR']
# If this response is a single row response, then we will throw
# an exception to alert the user of any failures.
if (len(lines) == 1):
raise ClickatellError(row['error'], row['code'])
finally:
result.append(row)
return result if len(result) > 1 else result[0]
def parseRest(self, response):
"""
Parse a REST response. If the response contains an error field, we will
raise it as an exception.
"""
body = json.loads(response)
try:
error = body['error']['description']
code = body['error']['code']
except Exception:
return body['data']
else:
raise ClickatellError(error, code);
def request(self, action, data={}, headers={}, method='GET'):
"""
Run the HTTP request against the Clickatell API
:param str action: The API action
:param dict data: The request parameters
:param dict headers: The request headers (if any)
:param str method: The HTTP method
:return: The request response
"""
url = ('https' if self.secure else 'http') + '://' + self.endpoint
url = url + '/' + action
# Set the User-Agent
userAgent = "".join(["ClickatellPython/0.1.2", " ", "Python/", platform.python_version()])
headers = self.merge({ "User-Agent": userAgent }, headers)
try:
func = getattr(requests, method.lower())
except AttributeError:
raise Exception('HTTP method ' + method + ' unsupported.')
resp = func(url, params=data, data=json.dumps(data), headers=headers)
# Set the coding before unwrapping the text
resp.encoding = 'utf-8'
content = resp.text
return content
def getStatus(self, status):
"""
Return the message status from the local diagnostic array. If the entry
is not found, we will return False
:return Return the diagnostic string or False
"""
try:
return self.status[status]
except Exception:
return False
def sendMessage(self, to, message, extra={}):
"""
Send a message.
:param list to: The number you want to send to (list of strings, or one string)
:param string message: The message you want to send
:param dict extra: Any extra parameters (see Clickatell documentation)
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()
def getBalance(self):
"""
Retrieve the user balance
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()
def stopMessage(self, apiMsgId):
"""
Retrieve the user balance
:param str apiMsgId: The API message ID
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()
def queryMessage(self, apiMsgId):
"""
Query a message status. Alias for getMessageCharge()
:param str apiMsgId: The API message ID
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()
def routeCoverage(self, msisdn):
"""
Query coverage for a specific number
:param str msisdn: The number to check coverage
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()
def getMessageCharge(self, apiMsgId):
"""
Query coverage for a specific number
:param str apiMsgId: The API message ID
:return dict
:raises NotImplementedError
"""
raise NotImplementedError()