[damned-lies: 3/4] Fixes #312 - Make uploading files via API pass through form validation




commit 88829c7a0d128337b4ada477897da365d2d94159
Author: Claude Paroz <claude 2xlibre net>
Date:   Wed Sep 7 19:59:23 2022 +0200

    Fixes #312 - Make uploading files via API pass through form validation

 api/tests.py | 17 +++++++++++++++++
 api/views.py | 23 +++++++++++++++++------
 2 files changed, 34 insertions(+), 6 deletions(-)
---
diff --git a/api/tests.py b/api/tests.py
index d18eb1a9..e9cc976b 100644
--- a/api/tests.py
+++ b/api/tests.py
@@ -2,6 +2,7 @@ from pathlib import Path
 
 from django.core import mail
 from django.core.files import File
+from django.core.files.uploadedfile import SimpleUploadedFile
 from django.test import TestCase
 from django.urls import reverse
 
@@ -200,6 +201,22 @@ class APIUploadTests(TestCase):
             response = self.client.post(self.url, data={'file': File(fh)})
             self.assertEqual(response.status_code, 403)
 
+    def test_upload_invalid_file(self):
+        state = self._get_module_state()
+        state.change_state(StateTranslating, person=self.translator)
+        self.client.force_login(self.translator)
+        response = self.client.post(self.url, data={
+            'file': SimpleUploadedFile('filename.po', b'No valid po file content')
+        })
+        err = '.po file does not pass “msgfmt -vc”. Please correct the file and try again.'
+        self.assertEqual(
+            response.json(),
+            {
+                'result': 'Error',
+                'error': {'file': [err]}
+            }
+        )
+
     def test_upload_translation(self):
         state = self._get_module_state()
         state.change_state(StateTranslating, person=self.translator)
diff --git a/api/views.py b/api/views.py
index 3e9a8943..c2d07f1f 100644
--- a/api/views.py
+++ b/api/views.py
@@ -14,6 +14,7 @@ from common.utils import check_gitlab_request
 from languages.models import Language
 from stats.models import Branch, Module, Release, Statistics
 from teams.models import Team
+from vertimus.forms import ActionForm
 from vertimus.models import ActionRT, ActionUT
 from vertimus.views import get_vertimus_state
 
@@ -255,14 +256,24 @@ class ReserveTranslationView(LoginRequiredMixin, VertimusPageMixin, View):
 class UploadTranslationView(LoginRequiredMixin, VertimusPageMixin, View):
     def post(self, request, *args, **kwargs):
         stats, state = self.get_state_from_kwargs()
-        actions = [x.name for x in state.get_available_actions(request.user.person)]
-        if 'UT' not in actions:
+        actions = state.get_available_actions(request.user.person)
+        if 'UT' not in [x.name for x in actions]:
             return HttpResponseForbidden('You cannot upload a translation to this module')
 
-        action = ActionUT(person=request.user.person, file=request.FILES.get('file'))
-        comment = request.POST.get('comment', '')
-        action.apply_on(state, {'comment': comment, 'send_to_ml': True})
-        return JsonResponse({'result': 'OK'})
+        action_form = ActionForm(
+            request.user, state, actions,
+            data={
+                'action': 'UT',
+                'comment': request.POST.get('comment', ''),
+            },
+            files=request.FILES,
+        )
+        if action_form.is_valid():
+            action = ActionUT(person=request.user.person, file=action_form.cleaned_data['file'])
+            action.apply_on(state, {'comment': action_form.cleaned_data['comment'], 'send_to_ml': True})
+            return JsonResponse({'result': 'OK'})
+        else:
+            return JsonResponse({'result': 'Error', 'error': action_form.errors})
 
 
 # CSRF skipped, verification using a secret token.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]