Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: cms/translations/xtm/xtm_api.py

Issue 29968558: Issue 7037 - [XTM Integration] Make REST API url customizable
Patch Set: Addressed comments Created Sept. 17, 2019, 12:22 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cms/translations/xtm/utils.py ('k') | tests/test_xtm_api.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # This file is part of the Adblock Plus web scripts, 1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-present eyeo GmbH 2 # Copyright (C) 2006-present eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details. 11 # GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License 13 # You should have received a copy of the GNU General Public License
14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 14 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
15 15
16 from __future__ import unicode_literals 16 from __future__ import unicode_literals
17 17
18 import json 18 import json
19 try:
20 import urlparse
21 except ImportError:
22 # It's Python 3
23 import urllib.parse as urlparse
19 24
20 import requests 25 import requests
21 26
22 __all__ = [ 27 __all__ = [
23 'XTMCloudAPI', 'XTMCloudException', 'get_token', 28 'XTMCloudAPI', 'XTMCloudException', 'get_token',
24 ] 29 ]
25 30
26 _BASE_URL = 'https://wstest2.xtm-intl.com/rest-api/' 31 _BASE_URL = 'https://wstest2.xtm-intl.com/rest-api/'
27 32
28 33
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 } 74 }
70 75
71 class _SuccessCodes: 76 class _SuccessCodes:
72 CREATE = 201 77 CREATE = 201
73 UPLOAD = 200 78 UPLOAD = 200
74 DOWNLOAD = 200 79 DOWNLOAD = 200
75 GET_TARGET_LANGS = 200 80 GET_TARGET_LANGS = 200
76 ADD_TARGET_LANGS = 200 81 ADD_TARGET_LANGS = 200
77 GET_WORKFLOW_IDS = 200 82 GET_WORKFLOW_IDS = 200
78 83
79 def __init__(self, token): 84 def __init__(self, token, base_url):
80 """Constructor. 85 """Constructor.
81 86
82 Parameters 87 Parameters
83 ---------- 88 ----------
84 token: str 89 token: str
85 Token used to authenticate with the API. 90 Token used to authenticate with the API.
91 base_url: str
92 Url used to connect to the API.
86 93
87 """ 94 """
88 self._token = token 95 self._token = token
89 self.base_url = _BASE_URL 96 self.base_url = base_url
90 97
91 def _execute(self, url, data=None, files=None, stream=False, 98 def _execute(self, url, data=None, files=None, stream=False,
92 params=None, headers=None): 99 params=None, headers=None):
93 """Send request to the API and return the response. 100 """Send request to the API and return the response.
94 101
95 Parameters 102 Parameters
96 ---------- 103 ----------
97 url: str 104 url: str
98 The url we're making the request to. 105 The url we're making the request to.
99 data: dict 106 data: dict
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 } 218 }
212 219
213 if files: 220 if files:
214 file_names, files_to_upload = self._construct_files_dict( 221 file_names, files_to_upload = self._construct_files_dict(
215 files, 'translationFiles[{}]') 222 files, 'translationFiles[{}]')
216 data.update(file_names) 223 data.update(file_names)
217 else: 224 else:
218 # Hacky way to go around 415 error code 225 # Hacky way to go around 415 error code
219 files_to_upload = {'a': 'b'} 226 files_to_upload = {'a': 'b'}
220 227
221 url = self.base_url + self._UrlPaths.CREATE 228 url = urlparse.urljoin(self.base_url, self._UrlPaths.CREATE)
222 229
223 response = self._execute(url, data=data, files=files_to_upload) 230 response = self._execute(url, data=data, files=files_to_upload)
224 231
225 if response.status_code != self._SuccessCodes.CREATE: 232 if response.status_code != self._SuccessCodes.CREATE:
226 # The creation was not successful 233 # The creation was not successful
234 print('Raising exception')
227 raise XTMCloudException(response.status_code, 235 raise XTMCloudException(response.status_code,
228 response.text.decode('utf-8'), 236 response.text.decode('utf-8'),
229 'creating job') 237 'creating job')
230 238
231 data = json.loads(response.text.encode('utf-8')) 239 data = json.loads(response.text.encode('utf-8'))
232 240
233 return data['projectId'], data['jobs'] 241 return data['projectId'], data['jobs']
234 242
235 def upload_files(self, files, project_id, overwrite=True): 243 def upload_files(self, files, project_id, overwrite=True):
236 """Upload a set of files to a project. 244 """Upload a set of files to a project.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 file_names, files_to_upload = self._construct_files_dict( 276 file_names, files_to_upload = self._construct_files_dict(
269 files, 'files[{}]', 277 files, 'files[{}]',
270 ) 278 )
271 279
272 if len(files_to_upload.keys()) == 0: 280 if len(files_to_upload.keys()) == 0:
273 raise Exception('Error: No files provided for upload.') 281 raise Exception('Error: No files provided for upload.')
274 282
275 data = {'matchType': self._MATCH_TYPE[overwrite]} 283 data = {'matchType': self._MATCH_TYPE[overwrite]}
276 data.update(file_names) 284 data.update(file_names)
277 285
278 url = self.base_url + self._UrlPaths.UPLOAD.format(project_id) 286 url = urlparse.urljoin(
287 self.base_url, self._UrlPaths.UPLOAD.format(project_id),
288 )
279 289
280 response = self._execute(url, data=data, files=files_to_upload) 290 response = self._execute(url, data=data, files=files_to_upload)
281 291
282 if response.status_code != self._SuccessCodes.UPLOAD: 292 if response.status_code != self._SuccessCodes.UPLOAD:
283 raise XTMCloudException(response.status_code, 293 raise XTMCloudException(response.status_code,
284 response.text.encode('utf-8'), 294 response.text.encode('utf-8'),
285 'uploading files') 295 'uploading files')
286 296
287 return json.loads(response.text.encode('utf-8'))['jobs'] 297 return json.loads(response.text.encode('utf-8'))['jobs']
288 298
(...skipping 11 matching lines...) Expand all
300 ------- 310 -------
301 bytes 311 bytes
302 The contents of the zip file returned by the API 312 The contents of the zip file returned by the API
303 313
304 Raises 314 Raises
305 ------ 315 ------
306 XTMCloudException 316 XTMCloudException
307 If the request is flawed in any way. 317 If the request is flawed in any way.
308 318
309 """ 319 """
310 url = (self.base_url + self._UrlPaths.DOWNLOAD).format(project_id) 320 url = urlparse.urljoin(
321 self.base_url, self._UrlPaths.DOWNLOAD.format(project_id),
322 )
311 323
312 exception_msg = { 324 exception_msg = {
313 400: 'Invalid request', 325 400: 'Invalid request',
314 401: 'Authentication failed', 326 401: 'Authentication failed',
315 500: 'Internal server error', 327 500: 'Internal server error',
316 404: 'Project not found.', 328 404: 'Project not found.',
317 } 329 }
318 330
319 response = self._execute(url, params={'fileType': files_type}, 331 response = self._execute(url, params={'fileType': files_type},
320 stream=True) 332 stream=True)
(...skipping 19 matching lines...) Expand all
340 ------- 352 -------
341 iterable 353 iterable
342 With the target languages for this project. 354 With the target languages for this project.
343 355
344 Raises 356 Raises
345 ------ 357 ------
346 XTMCloudException 358 XTMCloudException
347 If the request is unsuccessful. 359 If the request is unsuccessful.
348 360
349 """ 361 """
350 url = (self.base_url + self._UrlPaths.GET_TARGET_LANG).format( 362 url = urlparse.urljoin(
351 project_id, 363 self.base_url, self._UrlPaths.GET_TARGET_LANG.format(project_id),
352 ) 364 )
353 365
354 response = self._execute(url, stream=True) 366 response = self._execute(url, stream=True)
355 367
356 if response.status_code != self._SuccessCodes.GET_TARGET_LANGS: 368 if response.status_code != self._SuccessCodes.GET_TARGET_LANGS:
357 raise XTMCloudException(response.status_code, response.content, 369 raise XTMCloudException(response.status_code, response.content,
358 'extracting target languages') 370 'extracting target languages')
359 371
360 data = json.loads(response.content.encode('utf-8')) 372 data = json.loads(response.content.encode('utf-8'))
361 return {item['targetLanguage'] for item in data} 373 return {item['targetLanguage'] for item in data}
(...skipping 10 matching lines...) Expand all
372 384
373 Raises 385 Raises
374 ------- 386 -------
375 XTMCloudException 387 XTMCloudException
376 If the request to the API was not successful. 388 If the request to the API was not successful.
377 389
378 """ 390 """
379 data = json.dumps({ 391 data = json.dumps({
380 'targetLanguages': target_languages, 392 'targetLanguages': target_languages,
381 }) 393 })
382 url = (self.base_url + self._UrlPaths.ADD_TARGET_LANG).format( 394
383 project_id, 395 url = urlparse.urljoin(
396 self.base_url, self._UrlPaths.ADD_TARGET_LANG.format(project_id),
384 ) 397 )
398
385 headers = {'content-type': 'application/json'} 399 headers = {'content-type': 'application/json'}
386 400
387 response = self._execute(url, data=data, headers=headers) 401 response = self._execute(url, data=data, headers=headers)
388 402
389 if response.status_code != self._SuccessCodes.ADD_TARGET_LANGS: 403 if response.status_code != self._SuccessCodes.ADD_TARGET_LANGS:
390 raise XTMCloudException(response.status_code, response.content, 404 raise XTMCloudException(response.status_code, response.content,
391 'adding target languages to project') 405 'adding target languages to project')
392 406
393 def get_workflows_by_name(self, name): 407 def get_workflows_by_name(self, name):
394 """Get workflows with a specific name. 408 """Get workflows with a specific name.
395 409
396 Parameters 410 Parameters
397 ---------- 411 ----------
398 name: str 412 name: str
399 The name of the workflow we're looking for. 413 The name of the workflow we're looking for.
400 414
401 Returns 415 Returns
402 ------- 416 -------
403 iterable 417 iterable
404 Of workflow ids that match the name provided. 418 Of workflow ids that match the name provided.
405 419
406 """ 420 """
407 url = self.base_url + self._UrlPaths.GET_WORKFLOW_IDS 421 url = urlparse.urljoin(self.base_url, self._UrlPaths.GET_WORKFLOW_IDS)
408 422
409 response = self._execute(url, params={'name': name}) 423 response = self._execute(url, params={'name': name})
410 424
411 if response.status_code != self._SuccessCodes.GET_WORKFLOW_IDS: 425 if response.status_code != self._SuccessCodes.GET_WORKFLOW_IDS:
412 raise XTMCloudException(response.status_code, response.content, 426 raise XTMCloudException(response.status_code, response.content,
413 'extracting workflow ids') 427 'extracting workflow ids')
414 428
415 valid_ids = [] 429 valid_ids = []
416 for item in json.loads(response.content.encode('utf-8')): 430 for item in json.loads(response.content.encode('utf-8')):
417 if name.lower().replace(' ', '') == \ 431 if name.lower().replace(' ', '') == \
418 item['name'].lower().replace(' ', ''): 432 item['name'].lower().replace(' ', ''):
419 valid_ids.append(item['id']) 433 valid_ids.append(item['id'])
420 return valid_ids 434 return valid_ids
421 435
422 436
423 def get_token(username, password, user_id): 437 def get_token(username, password, user_id, base_url):
424 """Generate an API token from username and password. 438 """Generate an API token from username and password.
425 439
426 Parameters 440 Parameters
427 ---------- 441 ----------
428 username: str 442 username: str
429 The username used to generate the token. 443 The username used to generate the token.
430 password: str 444 password: str
431 The password used to generate the token. 445 The password used to generate the token.
432 user_id: int 446 user_id: int
433 The user ID used to generate the token. 447 The user ID used to generate the token.
448 base_url: str
449 The url used to connect to the API
434 450
435 Returns 451 Returns
436 ------- 452 -------
437 str 453 str
438 The resulting token generated by the API. 454 The resulting token generated by the API.
439 455
440 Raises 456 Raises
441 ------ 457 ------
442 XTMCloudException 458 XTMCloudException
443 If the credentials provided were invalid. 459 If the credentials provided were invalid.
444 460
445 """ 461 """
446 request_body = json.dumps({ 462 request_body = json.dumps({
447 'client': username, 463 'client': username,
448 'password': password, 464 'password': password,
449 'userId': user_id, 465 'userId': user_id,
450 }) 466 })
451 467
452 url = _BASE_URL + 'auth/token' 468 url = urlparse.urljoin(base_url, 'auth/token')
453 469
454 headers = {'content-type': 'application/json'} 470 headers = {'content-type': 'application/json'}
455 471
456 response = requests.post(url, data=request_body, headers=headers) 472 response = requests.post(url, data=request_body, headers=headers)
457 473
458 if response.status_code == 200: 474 if response.status_code == 200:
459 return json.loads(response.text)['token'].encode() 475 return json.loads(response.text)['token'].encode()
460 476
461 raise XTMCloudException(response.status_code, 477 raise XTMCloudException(response.status_code,
462 response.text.encode('utf-8'), 478 response.text.encode('utf-8'),
463 'generating token') 479 'generating token')
OLDNEW
« no previous file with comments | « cms/translations/xtm/utils.py ('k') | tests/test_xtm_api.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld