OLD | NEW |
(Empty) | |
| 1 # This file is part of the Adblock Plus web scripts, |
| 2 # Copyright (C) 2006-present eyeo GmbH |
| 3 # |
| 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 |
| 6 # published by the Free Software Foundation. |
| 7 # |
| 8 # Adblock Plus is distributed in the hope that it will be useful, |
| 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 # GNU General Public License for more details. |
| 12 # |
| 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/>. |
| 15 |
| 16 from flask import Flask, request, jsonify, Response, send_file |
| 17 |
| 18 import json |
| 19 |
| 20 from tests.utils import create_in_memory_zip |
| 21 from cms.translations.xtm.constants import SUPPORTED_LOCALES |
| 22 |
| 23 __all__ = [ |
| 24 'xtm_mock', |
| 25 'get_configured_app', |
| 26 ] |
| 27 |
| 28 _CREDENTIALS = { |
| 29 'token_gen_valid': {'client': 'admin', 'password': 'pass', 'userId': 20}, |
| 30 'token_gen_invalid': {'client': 'user', 'password': 'pass', 'userId': 50}, |
| 31 'token_valid': 'TheXTM-APIToken-VALID', |
| 32 'token_invalid': 'TheXTM-APIToken-INVALID', |
| 33 } |
| 34 |
| 35 _PROJECT_IDS = { |
| 36 'valid': 1234, |
| 37 'invalid': 1111, |
| 38 'valid-no-targetfiles': 9999, |
| 39 } |
| 40 |
| 41 _CREATION_MANDATORY_KEYS = {'workflowId', 'referenceId', 'name', |
| 42 'targetLanguages', 'customerId', 'description'} |
| 43 |
| 44 _CREATION_OPTIONAL_KEYS = {r'translationFiles\[(?P<idx>\d+)\].file', |
| 45 r'translationFiles\[(?P<idx>\d+)\].name'} |
| 46 |
| 47 xtm_mock = Flask('mocking-XTM') |
| 48 |
| 49 |
| 50 def get_configured_app(**kwargs): |
| 51 xtm_mock.config['rootdir'] = kwargs.pop('rootdir', '') |
| 52 xtm_mock.config['target_languages'] = kwargs.pop('target_langs', ['de_DE']) |
| 53 xtm_mock.config['files'] = kwargs.pop('files', []) |
| 54 xtm_mock.config['source_language'] = kwargs.pop('source_lang', 'en_US') |
| 55 return xtm_mock.wsgi_app |
| 56 |
| 57 |
| 58 def _check_auth(): |
| 59 try: |
| 60 auth = request.headers['Authorization'] |
| 61 except Exception: |
| 62 return False |
| 63 |
| 64 if auth != 'XTM-Basic ' + _CREDENTIALS['token_valid']: |
| 65 return False |
| 66 |
| 67 return True |
| 68 |
| 69 |
| 70 def _generate_jobs_list(): |
| 71 jobs = [] |
| 72 for lng in xtm_mock.config['target_languages']: |
| 73 for f in xtm_mock.config['files']: |
| 74 jobs.append({ |
| 75 'fileName': f['name'], |
| 76 'jobId': 1, |
| 77 'sourceLanguage': xtm_mock.config['source_language'], |
| 78 'targetLanguage': lng, |
| 79 }) |
| 80 |
| 81 return jobs |
| 82 |
| 83 |
| 84 @xtm_mock.route('/rest-api/auth/token', methods=['POST']) |
| 85 def authenticate(): |
| 86 if not request.is_json: |
| 87 return Response( |
| 88 status=400, |
| 89 response=json.dumps({'reason': 'Request body not a JSON.'}), |
| 90 ) |
| 91 |
| 92 credentials = request.json |
| 93 missing_keys = \ |
| 94 set(_CREDENTIALS['token_gen_valid'].keys()) - set(credentials.keys()) |
| 95 |
| 96 if len(missing_keys) > 0: |
| 97 return Response( |
| 98 status=400, |
| 99 response=json.dumps({'reason': 'Missing keys: {}'.format( |
| 100 missing_keys)}), |
| 101 ) |
| 102 |
| 103 if credentials == _CREDENTIALS['token_gen_valid']: |
| 104 return jsonify({'token': _CREDENTIALS['token_valid']}) |
| 105 |
| 106 if credentials == _CREDENTIALS['token_gen_invalid']: |
| 107 return jsonify({'token': _CREDENTIALS['token_invalid']}) |
| 108 |
| 109 return Response( |
| 110 status=400, |
| 111 response=json.dumps({'reason': 'Invalid credentials.'}), |
| 112 ) |
| 113 |
| 114 |
| 115 @xtm_mock.route('/rest-api/projects', methods=['POST']) |
| 116 def create_project(): |
| 117 if not _check_auth(): |
| 118 return Response( |
| 119 status=401, |
| 120 response=json.dumps({'reason': 'Authentication failed.'}), |
| 121 ) |
| 122 |
| 123 form_data = request.form.to_dict(flat=False) |
| 124 files = request.files.to_dict() |
| 125 xtm_mock.config['target_languages'] = form_data['targetLanguages'] |
| 126 keys_diff = _CREATION_MANDATORY_KEYS - set(form_data.keys()) |
| 127 |
| 128 if len(keys_diff) != 0: |
| 129 return Response( |
| 130 status=400, |
| 131 response=json.dumps( |
| 132 {'reason': 'Keys missing: {}'.format(keys_diff)}, |
| 133 ), |
| 134 ) |
| 135 |
| 136 # To make everything easier, just add the 1st file to the class |
| 137 if 'translationFiles[0].name' in form_data.keys(): |
| 138 xtm_mock.config['files'].append({ |
| 139 'name': form_data['translationFiles[0].name'][0], |
| 140 'data': files['translationFiles[0].file'], |
| 141 }) |
| 142 |
| 143 response_json = { |
| 144 'name': form_data['name'][0], |
| 145 'projectId': _PROJECT_IDS['valid'], |
| 146 'jobs': _generate_jobs_list(), |
| 147 } |
| 148 |
| 149 return Response(status=201, response=json.dumps(response_json)) |
| 150 |
| 151 |
| 152 @xtm_mock.route('/rest-api/projects/<int:project_id>/metrics', methods=['GET']) |
| 153 def get_metrics(project_id): |
| 154 if not _check_auth(): |
| 155 return Response( |
| 156 status=401, |
| 157 response=json.dumps({'reason': 'Authentication failed.'}), |
| 158 ) |
| 159 |
| 160 reply = [{ |
| 161 'coreMetrics': {}, |
| 162 'jobsMetrics': [], |
| 163 'metricsProgress': {}, |
| 164 'targetLanguage': tl, |
| 165 } for tl in xtm_mock.config['target_languages']] |
| 166 |
| 167 if project_id == _PROJECT_IDS['valid']: |
| 168 return jsonify(reply) |
| 169 |
| 170 return Response(status=404, response=json.dumps({'reason': 'Project not ' |
| 171 'found!'})) |
| 172 |
| 173 |
| 174 @xtm_mock.route('/rest-api/projects/<int:project_id>/target-languages', |
| 175 methods=['POST']) |
| 176 def add_languages(project_id): |
| 177 if not _check_auth(): |
| 178 return Response( |
| 179 status=401, |
| 180 response=json.dumps({'reason': 'Authentication failed.'}), |
| 181 ) |
| 182 if not request.is_json: |
| 183 return Response( |
| 184 status=400, |
| 185 response=json.dumps({'reason': 'Not a JSON.'}), |
| 186 ) |
| 187 |
| 188 for language in request.json['targetLanguages']: |
| 189 if language not in SUPPORTED_LOCALES: |
| 190 return Response( |
| 191 status=400, |
| 192 response=json.dumps( |
| 193 {'reason': 'Unsupported language: {''}'.format(language)}, |
| 194 ), |
| 195 ) |
| 196 |
| 197 xtm_mock.config['target_languages'] += request.json['targetLanguages'] |
| 198 response = { |
| 199 'jobs': _generate_jobs_list(), |
| 200 'projectId': project_id, |
| 201 'projectName': 'test-name', |
| 202 } |
| 203 |
| 204 if project_id == _PROJECT_IDS['valid']: |
| 205 return jsonify(response) |
| 206 |
| 207 return Response( |
| 208 status=404, |
| 209 response=json.dumps({'reason': 'Project not found!'}), |
| 210 ) |
| 211 |
| 212 |
| 213 @xtm_mock.route('/rest-api/projects/<int:project_id>/files/upload', |
| 214 methods=['POST']) |
| 215 def upload_and_update(project_id): |
| 216 if not _check_auth(): |
| 217 return Response( |
| 218 status=401, |
| 219 response='Authentication failed.', |
| 220 ) |
| 221 if project_id == _PROJECT_IDS['invalid']: |
| 222 return Response( |
| 223 status=404, |
| 224 response='Project not found!', |
| 225 ) |
| 226 |
| 227 data = request.form.to_dict() |
| 228 files = request.files.to_dict() |
| 229 |
| 230 xtm_mock.config['files'].append({ |
| 231 'name': data['files[0].name'], 'data': files['files[0].file'], |
| 232 }) |
| 233 |
| 234 return jsonify({ |
| 235 'project_id': 1234, |
| 236 'jobs': _generate_jobs_list(), |
| 237 }) |
| 238 |
| 239 |
| 240 @xtm_mock.route('/rest-api/projects/<int:project_id>/files/download', |
| 241 methods=['GET']) |
| 242 def download(project_id): |
| 243 if not _check_auth(): |
| 244 return Response( |
| 245 status=401, |
| 246 response=json.dumps({'reason': 'Authentication failed.'}), |
| 247 ) |
| 248 if project_id == _PROJECT_IDS['invalid']: |
| 249 return Response( |
| 250 status=404, |
| 251 response=json.dumps({'reason': 'Project not found.'}), |
| 252 ) |
| 253 if project_id == _PROJECT_IDS['valid-no-targetfiles']: |
| 254 return Response(status=200) |
| 255 |
| 256 names = [ |
| 257 '/'.join([target_lang, f['name']]) for f in xtm_mock.config['files'] |
| 258 for target_lang in xtm_mock.config['target_languages'] |
| 259 ] |
| 260 data = [ |
| 261 f['data'] for f in xtm_mock.config['files'] |
| 262 for _ in xtm_mock.config['target_languages'] |
| 263 ] |
| 264 |
| 265 zip_file = create_in_memory_zip(names, data) |
| 266 return send_file( |
| 267 zip_file, |
| 268 mimetype='application/zip', |
| 269 ) |
| 270 |
| 271 |
| 272 if __name__ == '__main__': |
| 273 xtm_mock.run(debug=True) |
OLD | NEW |