Skip to content

Commit 575d9b0

Browse files
authored
Merge pull request #161 from plivo/MPC_SDK_Changes
Mpc sdk changes
2 parents 43e8260 + 32b0fe7 commit 575d9b0

13 files changed

Lines changed: 210 additions & 34 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Change Log
22

3+
## [4.15.2](https://github.com/plivo/plivo-python/tree/v4.15.2) (2020-12-14)
4+
- Fix "Cannot import name 'encodestring' from 'base64'" error for Signature Validation-V2.
5+
6+
## [4.15.1](https://github.com/plivo/plivo-python/tree/v4.15.1) (2020-11-17)
7+
- Fix resource not found exception when making sequential requests.
8+
9+
## [4.15.0](https://github.com/plivo/plivo-python/tree/v4.15.0) (2020-11-17)
10+
- Add number_priority support for Powerpack API.
11+
12+
## [4.14.0](https://github.com/plivo/plivo-python/tree/v4.14.0) (2020-11-05)
13+
- Add Regulatory Compliance API Support.
14+
15+
## [4.13.0](https://github.com/plivo/plivo-python/tree/v4.13.0) (2020-10-23)
16+
- Change lookup API endpoint and response.
17+
318
## [4.12.0](https://github.com/plivo/plivo-python/tree/v4.12.0) (2020-10-06)
419
- Add lookup API support.
520

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ call_made = client.calls.create(
122122
import plivo
123123

124124
client = plivo.RestClient(auth_id='', auth_token='')
125-
resp = client.lookup.get("<insert-number-here>", info_type='carrier')
125+
resp = client.lookup.get("<insert-number-here>")
126126
print(resp)
127127
```
128128

plivo/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,4 @@ def gen():
243243
yield item
244244
offset += limit
245245

246-
return gen()
246+
return gen()

plivo/resources/lookup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from plivo.base import PlivoResourceInterface, ResponseObject
33

44

5+
LOOKUP_API_ENDPOINT = "https://lookup.plivo.com/v1/Number"
6+
7+
58
class Number(ResponseObject):
69
def __init__(self, client, data):
710
super(Number, self).__init__(data)
@@ -16,7 +19,7 @@ def get(self, number, info_type='carrier'):
1619
}
1720
return self.client.request(
1821
'GET',
19-
('Lookup/Number', number),
22+
(LOOKUP_API_ENDPOINT, number),
2023
data=params,
2124
response_type=Number,
22-
plivo_api_v1_base_url=True)
25+
is_lookup_request=True)

plivo/resources/numbers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def update(self,
118118
app_id=None,
119119
subaccount=None,
120120
alias=None,
121-
verification_info=None):
121+
verification_info=None,):
122122
return self.client.request('POST', ('Number', number),
123123
to_param_dict(self.update, locals()))
124124

plivo/resources/powerpacks.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,15 @@ class Powerpacks(PlivoResourceInterface):
330330
sticky_sender=[optional(of_type_exact(bool))],
331331
local_connect=[optional(of_type_exact(bool))],
332332
application_type=[optional(of_type(six.text_type))],
333-
application_id=[optional(of_type(six.text_type))])
333+
application_id=[optional(of_type(six.text_type))],
334+
number_priority=[optional(of_type_exact(list))])
334335
def create(self,
335336
name,
336337
sticky_sender=True,
337338
local_connect=True,
338339
application_type='',
339-
application_id=''):
340+
application_id='',
341+
number_priority=[]):
340342
if (name is None):
341343
raise ValidationError(
342344
'name parameter is invalid'
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
from plivo.base import (PlivoResource, PlivoResourceInterface)
2+
3+
4+
class EndUser(PlivoResource):
5+
_name = 'EndUser'
6+
_identifier_string = 'end_user'
7+
8+
9+
class EndUsers(PlivoResourceInterface):
10+
def __init__(self, client):
11+
self._resource_type = EndUser
12+
super(EndUsers, self).__init__(client)
13+
14+
def get(self, end_user_id):
15+
return self.client.request('GET', ('EndUser', end_user_id), response_type=EndUser)
16+
17+
def list(self, limit=None, offset=None, name=None, last_name=None, end_user_type=None):
18+
return self.client.request('GET', ('EndUser',), dict(limit=limit, offset=offset,
19+
name=name, last_name=last_name, end_user_type=end_user_type))
20+
21+
def create(self, name=None, last_name=None, end_user_type=None):
22+
return self.client.request('POST', ('EndUser',),
23+
dict(name=name, last_name=last_name, end_user_type=end_user_type))
24+
25+
def update(self, end_user_id=None, last_name=None, name=None, end_user_type=None):
26+
return self.client.request('POST', ('EndUser', end_user_id),
27+
dict(name=name, last_name=last_name, end_user_type=end_user_type))
28+
29+
def delete(self, end_user_id=None):
30+
return self.client.request('DELETE', ('EndUser', end_user_id))
31+
32+
33+
class ComplianceDocumentType(PlivoResource):
34+
_name = 'ComplianceDocumentType'
35+
_identifier_string = 'compliance_document_type'
36+
37+
38+
class ComplianceDocumentTypes(PlivoResourceInterface):
39+
def __init__(self, client):
40+
self._resource_type = EndUser
41+
super(ComplianceDocumentTypes, self).__init__(client)
42+
43+
def get(self, doc_id):
44+
return self.client.request('GET', ('ComplianceDocumentType', doc_id), response_type=ComplianceDocumentType)
45+
46+
def list(self, limit=None, offset=None):
47+
return self.client.request('GET', ('ComplianceDocumentType',), dict(limit=limit, offset=offset))
48+
49+
50+
class ComplianceDocument(PlivoResource):
51+
_name = 'ComplianceDocument'
52+
_identifier_string = 'compliance_document'
53+
54+
55+
class ComplianceDocuments(PlivoResourceInterface):
56+
def __init__(self, client):
57+
self._resource_type = EndUser
58+
super(ComplianceDocuments, self).__init__(client)
59+
60+
def get(self, compliance_document_id):
61+
return self.client.request('GET', ('ComplianceDocument', compliance_document_id),
62+
response_type=ComplianceDocument)
63+
64+
def list(self, limit=None, offset=None, end_user_id=None, document_type_id=None, alias=None):
65+
return self.client.request('GET', ('ComplianceDocument',), dict(limit=limit, offset=offset,
66+
end_user_id=end_user_id,
67+
document_type_id=document_type_id, alias=alias))
68+
69+
def create(self, end_user_id=None, document_type_id=None, alias=None, file=None, **data_fields):
70+
payload, files = construct_compliance_document_payload(end_user_id, document_type_id, alias, file, data_fields)
71+
return self.client.request('POST', ('ComplianceDocument',), payload, files=files)
72+
73+
def update(self, compliance_document_id=None, end_user_id=None, document_type_id=None, alias=None, file=None,
74+
**data_fields):
75+
payload, files = construct_compliance_document_payload(end_user_id, document_type_id, alias, file, data_fields)
76+
return self.client.request('POST', ('ComplianceDocument', compliance_document_id), payload, files=files)
77+
78+
def delete(self, compliance_document_id=None):
79+
return self.client.request('DELETE', ('ComplianceDocument', compliance_document_id))
80+
81+
82+
class ComplianceRequirement(PlivoResource):
83+
_name = 'ComplianceRequirement'
84+
_identifier_string = 'compliance_requirement'
85+
86+
87+
class ComplianceRequirements(PlivoResourceInterface):
88+
def __init__(self, client):
89+
self._resource_type = ComplianceRequirement
90+
super(ComplianceRequirements, self).__init__(client)
91+
92+
def get(self, compliance_requirement_id):
93+
return self.client.request('GET', ('ComplianceRequirement', compliance_requirement_id),
94+
response_type=ComplianceRequirement)
95+
96+
def list(self, country_iso2=None, number_type=None, end_user_type=None, phone_number=None):
97+
return self.client.request('GET', ('ComplianceRequirement',),
98+
dict(country_iso2=country_iso2, number_type=number_type,
99+
end_user_type=end_user_type, phone_number=phone_number), )
100+
101+
102+
class ComplianceApplication(PlivoResource):
103+
_name = 'ComplianceApplication'
104+
_identifier_string = 'compliance_application'
105+
106+
107+
class ComplianceApplications(PlivoResourceInterface):
108+
def __init__(self, client):
109+
self._resource_type = EndUser
110+
super(ComplianceApplications, self).__init__(client)
111+
112+
def get(self, compliance_application_id):
113+
return self.client.request('GET', ('ComplianceApplication', compliance_application_id),
114+
response_type=ComplianceApplication)
115+
116+
def list(self, status=None, end_user_type=None, number_type=None, country_iso2=None,
117+
alias=None, limit=None, offset=None, end_user_id=None):
118+
return self.client.request('GET', ('ComplianceApplication',),
119+
dict(status=status, end_user_type=end_user_type, number_type=number_type,
120+
country_iso2=country_iso2, alias=alias, limit=limit, offset=offset,
121+
end_user_id=end_user_id), )
122+
123+
def create(self, compliance_requirement_id=None, end_user_id=None, document_ids=None, alias=None,
124+
end_user_type=None, country_iso2=None, number_type=None):
125+
return self.client.request('POST', ('ComplianceApplication',),
126+
dict(compliance_requirement_id=compliance_requirement_id, end_user_id=end_user_id,
127+
alias=alias, document_ids=document_ids, end_user_type=end_user_type,
128+
country_iso2=country_iso2, number_type=number_type))
129+
130+
def update(self, compliance_application_id=None, document_ids=None):
131+
return self.client.request('POST', ('ComplianceApplication', compliance_application_id),
132+
dict(document_ids=document_ids))
133+
134+
def delete(self, compliance_application_id=None):
135+
return self.client.request('DELETE', ('ComplianceApplication', compliance_application_id))
136+
137+
def submit(self, compliance_application_id=None):
138+
return self.client.request('POST', ('ComplianceApplication', compliance_application_id, 'Submit'))
139+
140+
141+
# Helper methods
142+
def construct_compliance_document_payload(end_user_id, document_type_id, alias, file, data_fields):
143+
payload = dict(end_user_id=end_user_id, document_type_id=document_type_id, alias=alias)
144+
for key, value in data_fields.items():
145+
payload.update({key: value})
146+
files = {'file': ''}
147+
if file:
148+
files = {'file': open(file, 'rb')}
149+
return payload, files

plivo/rest/base_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ def create_request(self, method, path=None, data=None):
153153
req = Request(method, '/'.join([self.base_uri, self.session.auth[0]] +
154154
list([str(p) for p in path])) + '/',
155155
**({
156-
'params': data
157-
} if method == 'GET' else {
156+
'params': data
157+
} if method == 'GET' else {
158158
'json': data
159159
}))
160160
return self.session.prepare_request(req)
@@ -177,7 +177,7 @@ def create_multipart_request(self,
177177
req = Request(method,
178178
'/'.join([self.base_uri, self.multipart_session.auth[0]]
179179
+ list([str(p) for p in path])) + '/', **(
180-
data_args))
180+
data_args))
181181
return self.multipart_session.prepare_request(req)
182182

183183
def send_request(self, request, **kwargs):

plivo/rest/client.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
Numbers, Pricings, Recordings, Subaccounts, CallFeedback, MultiPartyCalls)
1818
from plivo.resources.live_calls import LiveCalls
1919
from plivo.resources.queued_calls import QueuedCalls
20+
from plivo.resources.regulatory_compliance import EndUsers, ComplianceDocumentTypes, ComplianceDocuments, \
21+
ComplianceRequirements, ComplianceApplications
2022
from plivo.utils import is_valid_mainaccount, is_valid_subaccount
2123
from plivo.version import __version__
2224
from requests import Request, Session
@@ -25,7 +27,6 @@
2527
'auth_id auth_token')
2628

2729
PLIVO_API = 'https://api.plivo.com'
28-
PLIVO_API_V1 = '/'.join([PLIVO_API, 'v1'])
2930
PLIVO_API_BASE_URI = '/'.join([PLIVO_API, 'v1/Account'])
3031

3132
# Will change these urls before putting this change in production
@@ -103,6 +104,11 @@ def __init__(self, auth_id=None, auth_token=None, proxies=None, timeout=5):
103104
self.addresses = Addresses(self)
104105
self.identities = Identities(self)
105106
self.call_feedback = CallFeedback(self)
107+
self.end_users = EndUsers(self)
108+
self.compliance_document_types = ComplianceDocumentTypes(self)
109+
self.compliance_documents = ComplianceDocuments(self)
110+
self.compliance_requirements = ComplianceRequirements(self)
111+
self.compliance_applications = ComplianceApplications(self)
106112
self.multi_party_calls = MultiPartyCalls(self)
107113
self.voice_retry_count = 0
108114

@@ -121,7 +127,6 @@ def process_response(self,
121127
"""Processes the API response based on the status codes and method used
122128
to access the API
123129
"""
124-
125130
try:
126131
response_json = response.json(
127132
object_hook=lambda x: ResponseObject(x) if isinstance(x, dict) else x)
@@ -207,21 +212,19 @@ def create_request(self, method, path=None, data=None, **kwargs):
207212
if 'is_callinsights_request' in kwargs:
208213
url = '/'.join([CALLINSIGHTS_BASE_URL, kwargs['callinsights_request_path']])
209214
req = Request(method, url, **({'params': data} if method == 'GET' else {'json': data}))
210-
elif kwargs.get('plivo_api_v1_base_url', False):
211-
# currently used by lookup API but can be used by other APIs in future
215+
elif kwargs.get('is_lookup_request', False):
212216
path = path or []
213-
url = '/'.join([PLIVO_API_V1] + list([str(p) for p in path]))
217+
url = '/'.join(list([str(p) for p in path]))
214218
req = Request(method, url, **({'params': data} if method == 'GET' else {'json': data}))
215219
else:
216220
path = path or []
217221
req = Request(method, '/'.join([self.base_uri, self.session.auth[0]] +
218222
list([str(p) for p in path])) + '/',
219223
**({
220-
'params': data
221-
} if method == 'GET' else {
224+
'params': data
225+
} if method == 'GET' else {
222226
'json': data
223227
}))
224-
225228
return self.session.prepare_request(req)
226229

227230
def create_multipart_request(self,
@@ -241,10 +244,8 @@ def create_multipart_request(self,
241244
data_args['files'] = files
242245
except Exception as e:
243246
print(e)
244-
req = Request(method,
245-
'/'.join([self.base_uri, self.multipart_session.auth[0]]
246-
+ list([str(p) for p in path])) + '/', **(
247-
data_args))
247+
url = '/'.join([self.base_uri, self.multipart_session.auth[0]] + list([str(p) for p in path])) + '/'
248+
req = Request(method, url, **data_args)
248249
return self.multipart_session.prepare_request(req)
249250

250251
def send_request(self, request, **kwargs):
@@ -268,6 +269,8 @@ def request(self,
268269
req = self.create_multipart_request(method, path, data, files)
269270
session = self.multipart_session
270271
else:
272+
if not kwargs.get("is_voice_request", False):
273+
self.base_uri = PLIVO_API_BASE_URI
271274
if data and 'is_callinsights_request' in data:
272275
params_dict = {}
273276
if 'callinsights_request_path' in data:
@@ -296,9 +299,9 @@ def request(self,
296299
kwargs["is_voice_request"] = True
297300
return self.request(method, path, data, **kwargs)
298301
return self.process_response(method, response, response_type, objects_type)
299-
elif kwargs.get('plivo_api_v1_base_url', False):
300-
req = self.create_request(method, path, data, plivo_api_v1_base_url=True)
301-
del kwargs['plivo_api_v1_base_url']
302+
elif kwargs.get('is_lookup_request', False):
303+
req = self.create_request(method, path, data, is_lookup_request=True)
304+
del kwargs['is_lookup_request']
302305
else:
303306
req = self.create_request(method, path, data)
304307
session = self.session

plivo/utils/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import re
44
from datetime import datetime
55

6-
from base64 import encodestring
76
from hmac import new as hnew
87
from hashlib import sha256
98
from .signature_v3 import validate_v3_signature
@@ -13,6 +12,11 @@
1312
except ImportError:
1413
from urlparse import urlparse, urlunparse
1514

15+
try:
16+
from base64 import encodebytes as base64_encode
17+
except ImportError:
18+
from base64 import encodestring as base64_encode
19+
1620

1721
def validate_signature(uri, nonce, signature, auth_token=''):
1822
"""
@@ -35,8 +39,8 @@ def validate_signature(uri, nonce, signature, auth_token=''):
3539
parsed_uri.path.decode('utf-8'), '', '',
3640
'')).encode('utf-8')
3741

38-
return encodestring(hnew(auth_token, base_url + nonce, sha256)
39-
.digest()).strip() == signature
42+
return base64_encode(hnew(auth_token, base_url + nonce, sha256)
43+
.digest()).strip() == signature
4044

4145

4246
def is_valid_time_comparison(time):

0 commit comments

Comments
 (0)