From 2063c5cebb568bdbc5a060f15daf06129f8c3457 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Mon, 3 Aug 2020 20:03:32 +0200
Subject: [PATCH 1/2] backoffice: ignore "only one" limit for agent submissions
 (#45711)

---
 tests/test_backoffice_pages.py | 27 +++++++++++++++++++++++++++
 wcs/backoffice/submission.py   |  3 +++
 wcs/forms/root.py              | 31 +++++++++++++++++++++----------
 3 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py
index 930c48729..66b1af11e 100644
--- a/tests/test_backoffice_pages.py
+++ b/tests/test_backoffice_pages.py
@@ -3380,6 +3380,33 @@ def test_backoffice_submission_with_nameid_and_channel(pub, local_user):
     assert formdata.status == 'wf-new'
 
 
+def test_backoffice_submission_only_one_check(pub, local_user):
+    user = create_user(pub)
+    create_environment(pub)
+
+    formdef = FormDef.get_by_urlname('form-title')
+    formdef.fields = [formdef.fields[0]]
+    formdef.backoffice_submission_roles = user.roles[:]
+    formdef.only_allow_one = True
+    formdef.enable_tracking_codes = True
+    formdef.store()
+
+    formdef.data_class().wipe()
+
+    # create a formdata attached the agent
+    formdata = formdef.data_class()()
+    formdata.user_id = user.id
+    formdata.just_created()
+    formdata.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/submission/form-title/')
+    resp.form['f1'] = 'test'
+    resp = resp.form.submit('submit')  # -> validation
+    resp = resp.form.submit('submit')  # -> submit
+    assert formdef.data_class().count() == 2
+
+
 def test_backoffice_wscall_failure_display(http_requests, pub):
     user = create_user(pub)
     create_environment(pub)
diff --git a/wcs/backoffice/submission.py b/wcs/backoffice/submission.py
index 83f36bec7..63718ad0a 100644
--- a/wcs/backoffice/submission.py
+++ b/wcs/backoffice/submission.py
@@ -146,6 +146,9 @@ class FormFillPage(PublicFormFillPage):
         else:
             raise errors.AccessUnauthorizedError()
 
+    def check_unique_submission(self):
+        return None
+
     def get_sidebar(self, data):
         r = TemplateIO(html=True)
 
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index 9c3046bee..fc1a180da 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -600,6 +600,16 @@ class FormPage(Directory, FormTemplateMixin):
                     root_url, _('Login with %s') % auth_contexts[auth_context])
         return r.getvalue()
 
+    def check_unique_submission(self):
+        if self.edit_mode:
+            return None
+        if not self.formdef.only_allow_one:
+            return None
+        for user_form in get_user_forms(self.formdef):
+            if not user_form.is_draft():
+                return user_form.id
+        return None
+
     _pages = None
     @property
     def pages(self):
@@ -694,10 +704,12 @@ class FormPage(Directory, FormTemplateMixin):
                 token = randbytes(8)
                 get_request().form['magictoken'] = token
                 session.add_magictoken(token, self.edited_data.data)
-        elif self.formdef.only_allow_one:
-            user_forms = get_user_forms(self.formdef)
-            if [x for x in user_forms if not x.is_draft()]:
-                return redirect('%s/' % user_forms[0].id)
+
+        # redirect to existing formdata if form is configured to only allow one
+        # per user and it's already there.
+        existing_form_id = self.check_unique_submission()
+        if existing_form_id:
+            return redirect('%s/' % existing_form_id)
 
         get_response().add_javascript(['jquery.js', 'qommon.forms.js'])
         form = Form()
@@ -1190,12 +1202,11 @@ class FormPage(Directory, FormTemplateMixin):
         if get_request().get_path().startswith('/backoffice/'):
             filled.user_id = None
 
-        if self.formdef.only_allow_one:
-            # this is already checked in _q_index but it's done a second time
-            # just before a new form is to be stored.
-            user_forms = get_user_forms(self.formdef)
-            if [x for x in user_forms if not x.is_draft()]:
-                return redirect('%s/' % user_forms[0].id)
+        # this is already checked in _q_index but it's done a second time
+        # just before a new form is to be stored.
+        existing_form_id = self.check_unique_submission()
+        if existing_form_id:
+            return redirect('%s/' % existing_form_id)
 
         filled.store()
         self.set_tracking_code(filled)
-- 
2.28.0

