OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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') |
OLD | NEW |