44import requests
55from requests .exceptions import RequestException
66
7+ from crossengage .utils import update_dict
78
89class CrossengageClient (object ):
910 """
@@ -39,11 +40,18 @@ class CrossengageClient(object):
3940
4041 """
4142 API_URL = 'https://api.crossengage.io'
42- API_VERSION = '1'
43+ API_VERSIONS = {
44+ "v1" : "1" ,
45+ "v2" : "2"
46+ }
4347
44- USER_ENDPOINT = '/users/'
45- EVENTS_ENDPOINT = '/events'
46- BULK_ENDPOINT = '/users/batch'
48+ AUTH_HEADER = 'X-XNG-AuthToken'
49+ API_VERSION_HEADER = 'X-XNG-ApiVersion'
50+
51+ USER_ENDPOINT = 'users'
52+ USER_BULK_ENDPOINT = "{0}/batch" .format (USER_ENDPOINT )
53+ TRACK_USER_TASK_ENDPOINT = "{0}/track" .format (USER_ENDPOINT )
54+ EVENTS_ENDPOINT = 'events'
4755
4856 REQUEST_GET = 'get'
4957 REQUEST_PUT = 'put'
@@ -62,12 +70,33 @@ def __init__(self, client_token):
6270 self .client_token = client_token
6371 self .requests = requests
6472 self .request_url = ''
65- self .headers = {
66- 'X-XNG-AuthToken' : self .client_token ,
67- 'X-XNG-ApiVersion' : self .API_VERSION ,
73+ self .default_headers = {
74+ self . AUTH_HEADER : self .client_token ,
75+ self . API_VERSION_HEADER : self .API_VERSIONS [ "v1" ] ,
6876 'Content-Type' : 'application/json' ,
6977 }
7078
79+ def get_user (self , user ):
80+ # type: (dict) -> dict
81+ """
82+ Fetch User by id.
83+ :param user: dict of payload (id, email, businessUnit, firstName, lastName, birthday, createdAt, gender)
84+ :return: json dict response, for example:
85+ {
86+ "status_code": 200,
87+ "email": "john.doe@crossengage.io",
88+ "id": "fb85fe50-a528-11e7-abc4-cec278b6b50a",
89+ "xngId": "123e4567-e89b-12d3-a456-426655440000",
90+ "firstName": "John",
91+ "lastName": "Doe",
92+ "birthday": "1982-08-30",
93+ "createdAt": "2015-10-02T08:23:53Z",
94+ "gender": "male"
95+ }
96+ """
97+ self .request_url = "{0}/{1}/{2}" .format (self .API_URL , self .USER_ENDPOINT , user ['id' ])
98+ return self .__create_request (payload = {}, request_type = self .REQUEST_GET , version = "v2" )
99+
71100 def update_user (self , user ):
72101 # type: (dict) -> dict
73102 """
@@ -76,8 +105,19 @@ def update_user(self, user):
76105 :return: json dict response, for example: {"status_code": 200, "id":"123", "xngGlobalUserId": "xng-id",
77106 "success": "true}
78107 """
79- self .request_url = self .API_URL + self .USER_ENDPOINT + user ['id' ]
80- return self .__create_request (payload = user , request_type = self .REQUEST_PUT )
108+ self .request_url = "{0}/{1}/{2}" .format (self .API_URL , self .USER_ENDPOINT , user ['id' ])
109+ return self .__create_request (payload = user , request_type = self .REQUEST_PUT , version = "v1" )
110+
111+ def update_user_async (self , user ):
112+ # type: (dict) -> dict
113+ """
114+ Create / Update User given its id and email.
115+ :param user: dict of payload (id, email, businessUnit, firstName, lastName, birthday, createdAt, gender)
116+ :return: json dict response, for example:
117+ {"status_code": 202, "trackingId": "2e312089-a987-45c6-adbd-b904bc4dfc97"}
118+ """
119+ self .request_url = "{0}/{1}" .format (self .API_URL , self .USER_ENDPOINT )
120+ return self .__create_request (payload = user , request_type = self .REQUEST_PUT , version = "v2" )
81121
82122 def update_users_bulk (self , users ):
83123 # type: (list) -> dict
@@ -88,8 +128,8 @@ def update_users_bulk(self, users):
88128 :return: json dict response
89129 """
90130 payload = {'updated' : users }
91- self .request_url = self .API_URL + self .USER_ENDPOINT + 'batch'
92- return self .__create_request (payload = payload , request_type = self .REQUEST_POST )
131+ self .request_url = "{0}/{1}" . format ( self .API_URL , self .USER_BULK_ENDPOINT )
132+ return self .__create_request (payload = payload , request_type = self .REQUEST_POST , version = "v1" )
93133
94134 def delete_user (self , user ):
95135 # type: (dict) -> dict
@@ -98,8 +138,19 @@ def delete_user(self, user):
98138 :param user: dict of payload (id)
99139 :return: json dict response, for example: {"status_code": 200}
100140 """
101- self .request_url = self .API_URL + self .USER_ENDPOINT + user ['id' ]
102- return self .__create_request (payload = user , request_type = self .REQUEST_DELETE )
141+ self .request_url = "{0}/{1}/{2}" .format (self .API_URL , self .USER_ENDPOINT , user ['id' ])
142+ return self .__create_request (payload = user , request_type = self .REQUEST_DELETE , version = "v1" )
143+
144+ def delete_user_async (self , user ):
145+ # type: (dict) -> dict
146+ """
147+ Delete User given its id.
148+ :param user: dict of payload (id)
149+ :return: json dict response, for example:
150+ {"status_code": 202, "trackingId": "2e312089-a987-45c6-adbd-b904bc4dfc97"}
151+ """
152+ self .request_url = "{0}/{1}/{2}" .format (self .API_URL , self .USER_ENDPOINT , user ['id' ])
153+ return self .__create_request (payload = user , request_type = self .REQUEST_DELETE , version = "v2" )
103154
104155 def delete_user_by_xng_id (self , user ):
105156 # type: (dict) -> dict
@@ -108,8 +159,8 @@ def delete_user_by_xng_id(self, user):
108159 :param user: dict of payload (xng_id)
109160 :return: json dict response, for example: {"status_code": 200}
110161 """
111- self .request_url = self .API_URL + self .USER_ENDPOINT + 'xngId/' + user ['xngId' ]
112- return self .__create_request (payload = user , request_type = self .REQUEST_DELETE )
162+ self .request_url = "{0}/{1}/xngId/{2}" . format ( self .API_URL , self .USER_ENDPOINT , user ['xngId' ])
163+ return self .__create_request (payload = user , request_type = self .REQUEST_DELETE , version = "v1" )
113164
114165 def add_user_attribute (self , attribute_name , attribute_type , nested_type ):
115166 """
@@ -120,13 +171,13 @@ def add_user_attribute(self, attribute_name, attribute_type, nested_type):
120171 :return: json dict response, for example: {"id": 123, "name":"traits.foobar", "attributeType": "ARRAY",
121172 "success": "true}
122173 """
123- self .request_url = self .API_URL + self .USER_ENDPOINT + 'attributes'
174+ self .request_url = "{0}/{1}/attributes" . format ( self .API_URL , self .USER_ENDPOINT )
124175 payload = {
125176 'name' : 'traits.' + attribute_name ,
126177 'attributeType' : attribute_type ,
127178 'nestedType' : nested_type
128179 }
129- return self .__create_request (payload , self .REQUEST_POST )
180+ return self .__create_request (payload , self .REQUEST_POST , version = "v1" )
130181
131182 def add_nested_user_attribute (self , parent_name , attribute_name , attribute_type ):
132183 """
@@ -137,13 +188,13 @@ def add_nested_user_attribute(self, parent_name, attribute_name, attribute_type)
137188 :return: json dict response, for example: {"id": 123, "name":"traits.foobar", "attributeType": "ARRAY",
138189 "success": "true}
139190 """
140- self .request_url = self .API_URL + self .USER_ENDPOINT + 'attributes'
191+ self .request_url = "{0}/{1}/attributes" . format ( self .API_URL , self .USER_ENDPOINT )
141192 payload = {
142193 'name' : attribute_name ,
143194 'attributeType' : attribute_type ,
144195 'parentName' : parent_name
145196 }
146- return self .__create_request (payload , self .REQUEST_POST )
197+ return self .__create_request (payload , self .REQUEST_POST , version = "v1" )
147198
148199 def list_user_attributes (self , offset , limit ):
149200 """
@@ -155,17 +206,19 @@ def list_user_attributes(self, offset, limit):
155206 """
156207 self .request_url = self .API_URL + self .USER_ENDPOINT + 'attributes?offset=' + str (offset ) + '&limit=' + str (
157208 limit )
158- return self .__create_request (None , self .REQUEST_GET )
209+ self .request_url = "{0}/{1}/attributes?offset={2}&limit={3}" .format (
210+ self .API_URL , self .USER_ENDPOINT , offset , limit )
211+ return self .__create_request (None , self .REQUEST_GET , version = "v1" )
159212
160213 def delete_user_attribute (self , attribute_id ):
161214 """
162215 Delete user attribute.
163216 :param attribute_id: id of attribute
164217 :return: response N/A or error_response
165218 """
166- self .request_url = self .API_URL + self .USER_ENDPOINT + 'attributes/' + str ( attribute_id )
219+ self .request_url = "{0}/{1}/attributes/{2}" . format ( self .API_URL , self .USER_ENDPOINT , attribute_id )
167220 payload = {}
168- return self .__create_request (payload , self .REQUEST_DELETE )
221+ return self .__create_request (payload , self .REQUEST_DELETE , version = "v1" )
169222
170223 def send_events (self , events , email = None , user_id = None , business_unit = None ):
171224 """
@@ -176,7 +229,7 @@ def send_events(self, events, email=None, user_id=None, business_unit=None):
176229 :param user_id: id of user in your database
177230 :return: json dict response, for example: {"status_code": 200}
178231 """
179- self .request_url = "{}{ }" .format (self .API_URL , self .EVENTS_ENDPOINT )
232+ self .request_url = "{0}/{1 }" .format (self .API_URL , self .EVENTS_ENDPOINT )
180233
181234 if email is None and user_id is None :
182235 raise ValueError ('email or external_id required for sending events' )
@@ -194,7 +247,7 @@ def send_events(self, events, email=None, user_id=None, business_unit=None):
194247 if business_unit is not None :
195248 payload ['businessUnit' ] = business_unit
196249
197- return self .__create_request (payload , self .REQUEST_POST )
250+ return self .__create_request (payload , self .REQUEST_POST , version = "v1" )
198251
199252 def batch_process (self , delete_list = [], update_list = []):
200253 """
@@ -239,7 +292,7 @@ def batch_process(self, delete_list=[], update_list=[]):
239292 ]
240293 }
241294 """
242- self .request_url = self .API_URL + self .BULK_ENDPOINT
295+ self .request_url = "{0}/{1}" . format ( self .API_URL , self .USER_BULK_ENDPOINT )
243296 payload = {
244297 'updated' : update_list ,
245298 'deleted' : delete_list ,
@@ -248,25 +301,60 @@ def batch_process(self, delete_list=[], update_list=[]):
248301 r = self .requests .post (
249302 self .request_url ,
250303 data = json .dumps (payload ),
251- headers = self .headers
304+ headers = self .default_headers
252305 )
253306
254307 return r .status_code , r .json ()
255308
256- def __create_request (self , payload , request_type ):
257- r = '{}'
309+ def batch_process_async (self , delete_list = [], update_list = []):
310+ """
311+ Create, Update or Delete up to 1000 users in batch.
312+ :param delete_list: users that should be deleted
313+ :param update_list: users that should be created or updated
314+ :return integer status_code, json dict response
315+ 202, {"trackingId": "2e312089-a987-45c6-adbd-b904bc4dfc97"}
316+ """
317+ headers = update_dict (self .default_headers , {self .API_VERSION_HEADER : self .API_VERSIONS ["v2" ]})
318+ self .request_url = "{0}/{1}" .format (self .API_URL , self .USER_BULK_ENDPOINT )
319+
320+ payload = {
321+ 'updated' : update_list ,
322+ 'deleted' : delete_list ,
323+ }
324+
325+ r = self .requests .post (self .request_url , data = json .dumps (payload ), headers = headers )
326+
327+ return r .status_code , r .json ()
328+
329+ def track_user_task (self , tracking_id ):
330+ # type: (dict) -> dict
331+ """
332+ Create / Update User given its id.
333+ :param user: dict of payload (email, id, firstName, lastName, birthday, createdAt, gender)
334+ :return integer status_code, json dict response
335+ 200, { "stage": "PROCESSED", "total": 2, "success": 1, "error": 1 }
336+ """
337+ headers = update_dict (self .default_headers , {self .API_VERSION_HEADER : self .API_VERSIONS ["v2" ]})
338+ self .request_url = "{0}/{1}/{2}" .format (self .API_URL , self .TRACK_USER_TASK_ENDPOINT , tracking_id )
339+
340+ r = self .requests .get (self .request_url , headers = headers )
341+
342+ return r .status_code , r .json ()
343+
344+ def __create_request (self , payload , request_type , version ):
345+ headers = update_dict (self .default_headers , {self .API_VERSION_HEADER : self .API_VERSIONS [version ]})
258346 try :
259347 if request_type == self .REQUEST_PUT :
260- r = self .requests .put (self .request_url , data = json .dumps (payload ), headers = self . headers )
348+ r = self .requests .put (self .request_url , data = json .dumps (payload ), headers = headers )
261349
262350 if request_type == self .REQUEST_GET :
263- r = self .requests .get (self .request_url , headers = self . headers )
351+ r = self .requests .get (self .request_url , headers = headers )
264352
265353 if request_type == self .REQUEST_POST :
266- r = self .requests .post (self .request_url , data = json .dumps (payload ), headers = self . headers )
354+ r = self .requests .post (self .request_url , data = json .dumps (payload ), headers = headers )
267355
268356 if request_type == self .REQUEST_DELETE :
269- r = self .requests .delete (self .request_url , data = json .dumps (payload ), headers = self . headers )
357+ r = self .requests .delete (self .request_url , data = json .dumps (payload ), headers = headers )
270358
271359 response = {}
272360 if r .text != '' :
0 commit comments