Left: | ||
Right: |
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.bin.xtm_translations.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.get('Authorization') | |
Vasily Kuznetsov
2018/09/26 15:45:27
Can this just be `request.headers['Authorization']
Tudor Avram
2018/10/04 06:48:15
Done.
| |
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']] | |
Vasily Kuznetsov
2018/09/26 15:45:27
Nit: space before "for"?
Tudor Avram
2018/10/04 06:48:16
Done.
| |
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 |