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