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: Created Dec. 27, 2018, 2:23 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
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
227 raise XTMCloudException(response.status_code, 234 raise XTMCloudException(response.status_code,
228 response.text.decode('utf-8'), 235 response.text.decode('utf-8'),
229 'creating job') 236 'creating job')
230 237
231 data = json.loads(response.text.encode('utf-8')) 238 data = json.loads(response.text.encode('utf-8'))
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 file_names, files_to_upload = self._construct_files_dict( 275 file_names, files_to_upload = self._construct_files_dict(
269 files, 'files[{}]', 276 files, 'files[{}]',
270 ) 277 )
271 278
272 if len(files_to_upload.keys()) == 0: 279 if len(files_to_upload.keys()) == 0:
273 raise Exception('Error: No files provided for upload.') 280 raise Exception('Error: No files provided for upload.')
274 281
275 data = {'matchType': self._MATCH_TYPE[overwrite]} 282 data = {'matchType': self._MATCH_TYPE[overwrite]}
276 data.update(file_names) 283 data.update(file_names)
277 284
278 url = self.base_url + self._UrlPaths.UPLOAD.format(project_id) 285 url = urlparse.urljoin(
286 self.base_url, self._UrlPaths.UPLOAD.format(project_id),
287 )
279 288
280 response = self._execute(url, data=data, files=files_to_upload) 289 response = self._execute(url, data=data, files=files_to_upload)
281 290
282 if response.status_code != self._SuccessCodes.UPLOAD: 291 if response.status_code != self._SuccessCodes.UPLOAD:
283 raise XTMCloudException(response.status_code, 292 raise XTMCloudException(response.status_code,
284 response.text.encode('utf-8'), 293 response.text.encode('utf-8'),
285 'uploading files') 294 'uploading files')
286 295
287 return json.loads(response.text.encode('utf-8'))['jobs'] 296 return json.loads(response.text.encode('utf-8'))['jobs']
288 297
(...skipping 11 matching lines...) Expand all
300 ------- 309 -------
301 bytes 310 bytes
302 The contents of the zip file returned by the API 311 The contents of the zip file returned by the API
303 312
304 Raises 313 Raises
305 ------ 314 ------
306 XTMCloudException 315 XTMCloudException
307 If the request is flawed in any way. 316 If the request is flawed in any way.
308 317
309 """ 318 """
310 url = (self.base_url + self._UrlPaths.DOWNLOAD).format(project_id) 319 url = urlparse.urljoin(
320 self.base_url, self._UrlPaths.DOWNLOAD.format(project_id),
321 )
311 322
312 exception_msg = { 323 exception_msg = {
313 400: 'Invalid request', 324 400: 'Invalid request',
314 401: 'Authentication failed', 325 401: 'Authentication failed',
315 500: 'Internal server error', 326 500: 'Internal server error',
316 404: 'Project not found.', 327 404: 'Project not found.',
317 } 328 }
318 329
319 response = self._execute(url, params={'fileType': files_type}, 330 response = self._execute(url, params={'fileType': files_type},
320 stream=True) 331 stream=True)
(...skipping 19 matching lines...) Expand all
340 ------- 351 -------
341 iterable 352 iterable
342 With the target languages for this project. 353 With the target languages for this project.
343 354
344 Raises 355 Raises
345 ------ 356 ------
346 XTMCloudException 357 XTMCloudException
347 If the request is unsuccessful. 358 If the request is unsuccessful.
348 359
349 """ 360 """
350 url = (self.base_url + self._UrlPaths.GET_TARGET_LANG).format( 361 url = urlparse.urljoin(
351 project_id, 362 self.base_url, self._UrlPaths.GET_TARGET_LANG.format(project_id),
352 ) 363 )
353 364
354 response = self._execute(url, stream=True) 365 response = self._execute(url, stream=True)
355 366
356 if response.status_code != self._SuccessCodes.GET_TARGET_LANGS: 367 if response.status_code != self._SuccessCodes.GET_TARGET_LANGS:
357 raise XTMCloudException(response.status_code, response.content, 368 raise XTMCloudException(response.status_code, response.content,
358 'extracting target languages') 369 'extracting target languages')
359 370
360 data = json.loads(response.content.encode('utf-8')) 371 data = json.loads(response.content.encode('utf-8'))
361 return {item['targetLanguage'] for item in data} 372 return {item['targetLanguage'] for item in data}
(...skipping 10 matching lines...) Expand all
372 383
373 Raises 384 Raises
374 ------- 385 -------
375 XTMCloudException 386 XTMCloudException
376 If the request to the API was not successful. 387 If the request to the API was not successful.
377 388
378 """ 389 """
379 data = json.dumps({ 390 data = json.dumps({
380 'targetLanguages': target_languages, 391 'targetLanguages': target_languages,
381 }) 392 })
382 url = (self.base_url + self._UrlPaths.ADD_TARGET_LANG).format( 393
383 project_id, 394 url = urlparse.urljoin(
395 self.base_url, self._UrlPaths.ADD_TARGET_LANG.format(project_id),
384 ) 396 )
397
385 headers = {'content-type': 'application/json'} 398 headers = {'content-type': 'application/json'}
386 399
387 response = self._execute(url, data=data, headers=headers) 400 response = self._execute(url, data=data, headers=headers)
388 401
389 if response.status_code != self._SuccessCodes.ADD_TARGET_LANGS: 402 if response.status_code != self._SuccessCodes.ADD_TARGET_LANGS:
390 raise XTMCloudException(response.status_code, response.content, 403 raise XTMCloudException(response.status_code, response.content,
391 'adding target languages to project') 404 'adding target languages to project')
392 405
393 def get_workflows_by_name(self, name): 406 def get_workflows_by_name(self, name):
394 """Get workflows with a specific name. 407 """Get workflows with a specific name.
395 408
396 Parameters 409 Parameters
397 ---------- 410 ----------
398 name: str 411 name: str
399 The name of the workflow we're looking for. 412 The name of the workflow we're looking for.
400 413
401 Returns 414 Returns
402 ------- 415 -------
403 iterable 416 iterable
404 Of workflow ids that match the name provided. 417 Of workflow ids that match the name provided.
405 418
406 """ 419 """
407 url = self.base_url + self._UrlPaths.GET_WORKFLOW_IDS 420 url = urlparse.urljoin(self.base_url, self._UrlPaths.GET_WORKFLOW_IDS)
408 421
409 response = self._execute(url, params={'name': name}) 422 response = self._execute(url, params={'name': name})
410 423
411 if response.status_code != self._SuccessCodes.GET_WORKFLOW_IDS: 424 if response.status_code != self._SuccessCodes.GET_WORKFLOW_IDS:
412 raise XTMCloudException(response.status_code, response.content, 425 raise XTMCloudException(response.status_code, response.content,
413 'extracting workflow ids') 426 'extracting workflow ids')
414 427
415 valid_ids = [] 428 valid_ids = []
416 for item in json.loads(response.content.encode('utf-8')): 429 for item in json.loads(response.content.encode('utf-8')):
417 if name.lower().replace(' ', '') == \ 430 if name.lower().replace(' ', '') == \
418 item['name'].lower().replace(' ', ''): 431 item['name'].lower().replace(' ', ''):
419 valid_ids.append(item['id']) 432 valid_ids.append(item['id'])
420 return valid_ids 433 return valid_ids
421 434
422 435
423 def get_token(username, password, user_id): 436 def get_token(username, password, user_id, base_url):
424 """Generate an API token from username and password. 437 """Generate an API token from username and password.
425 438
426 Parameters 439 Parameters
427 ---------- 440 ----------
428 username: str 441 username: str
429 The username used to generate the token. 442 The username used to generate the token.
430 password: str 443 password: str
431 The password used to generate the token. 444 The password used to generate the token.
432 user_id: int 445 user_id: int
433 The user ID used to generate the token. 446 The user ID used to generate the token.
447 base_url: str
448 The url used to connect to the API
434 449
435 Returns 450 Returns
436 ------- 451 -------
437 str 452 str
438 The resulting token generated by the API. 453 The resulting token generated by the API.
439 454
440 Raises 455 Raises
441 ------ 456 ------
442 XTMCloudException 457 XTMCloudException
443 If the credentials provided were invalid. 458 If the credentials provided were invalid.
444 459
445 """ 460 """
446 request_body = json.dumps({ 461 request_body = json.dumps({
447 'client': username, 462 'client': username,
448 'password': password, 463 'password': password,
449 'userId': user_id, 464 'userId': user_id,
450 }) 465 })
451 466
452 url = _BASE_URL + 'auth/token' 467 url = urlparse.urljoin(base_url, 'auth/token')
453 468
454 headers = {'content-type': 'application/json'} 469 headers = {'content-type': 'application/json'}
455 470
456 response = requests.post(url, data=request_body, headers=headers) 471 response = requests.post(url, data=request_body, headers=headers)
457 472
458 if response.status_code == 200: 473 if response.status_code == 200:
459 return json.loads(response.text)['token'].encode() 474 return json.loads(response.text)['token'].encode()
460 475
461 raise XTMCloudException(response.status_code, 476 raise XTMCloudException(response.status_code,
462 response.text.encode('utf-8'), 477 response.text.encode('utf-8'),
463 'generating token') 478 'generating token')
OLDNEW

Powered by Google App Engine
This is Rietveld