From d42fce3352ec6f4da9d222bf4304b646f822b940 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Mon, 20 Sep 2021 18:12:37 +0200
Subject: [PATCH] general: directly apply formdef/carddef schema changes
 (#57118)

---
 tests/backoffice_pages/test_all.py |  1 +
 tests/test_formdata.py             | 10 ++++++++++
 wcs/carddef.py                     | 10 ++--------
 wcs/formdef.py                     | 31 +++++++++++++++---------------
 wcs/sql.py                         |  2 +-
 wcs/workflows.py                   |  4 ++--
 6 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/tests/backoffice_pages/test_all.py b/tests/backoffice_pages/test_all.py
index 225e91f9d..6f999fb50 100644
--- a/tests/backoffice_pages/test_all.py
+++ b/tests/backoffice_pages/test_all.py
@@ -1961,6 +1961,7 @@ def test_backoffice_geojson(pub):
     formdef = FormDef.get_by_urlname('form-title')
     formdef.fields.append(fields.MapField(id='4', label='4th field', type='map'))
     formdef.fields.append(fields.MapField(id='5', label='5th field', type='string'))
+    formdef.store()
     form_class = formdef.data_class()
     number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
     app = login(get_app(pub))
diff --git a/tests/test_formdata.py b/tests/test_formdata.py
index 6338ae899..9aa78feb0 100644
--- a/tests/test_formdata.py
+++ b/tests/test_formdata.py
@@ -2422,6 +2422,7 @@ def test_form_digest_date(pub):
 
 
 def test_form_digest_error(pub):
+    FormDef.wipe()
     if pub.is_using_postgresql():
         pub.loggederror_class.wipe()
 
@@ -2460,6 +2461,7 @@ def test_form_digest_error(pub):
 
 
 def test_lazy_formdata_decimal_filter(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2489,6 +2491,7 @@ def test_lazy_formdata_decimal_filter(pub):
 
 
 def test_lazy_formdata_timesince_filter(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2534,6 +2537,7 @@ def test_decimal_conditions_django(pub, variable_test_data):
 
 
 def test_lazy_formdata_mathematics_filters(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2566,6 +2570,7 @@ def test_lazy_formdata_mathematics_filters(pub):
 
 
 def test_lazy_formdata_add_filters(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2702,6 +2707,7 @@ def test_mathematic_conditions_django(pub, variable_test_data):
 
 
 def test_lazy_formdata_ceil_filter(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2724,6 +2730,7 @@ def test_lazy_formdata_ceil_filter(pub):
 
 
 def test_lazy_formdata_count_as_len_filter(pub):
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2785,6 +2792,7 @@ def test_lazy_url_suffix(pub, variable_test_data):
         ),
     }
 
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2825,6 +2833,7 @@ def test_lazy_structured_items(pub, variable_test_data):
         'value': repr([{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}]),
     }
 
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
@@ -2925,6 +2934,7 @@ def test_user_label(pub):
     pub.cfg['users']['field_name'] = ['3', '4']
     pub.write_cfg()
 
+    FormDef.wipe()
     formdef = FormDef()
     formdef.name = 'foobar'
     formdef.url_name = 'foobar'
diff --git a/wcs/carddef.py b/wcs/carddef.py
index 797f7f4f7..5c057296a 100644
--- a/wcs/carddef.py
+++ b/wcs/carddef.py
@@ -60,21 +60,15 @@ class CardDef(FormDef):
             cls = types.ClassType(
                 self.data_class_name, (sql.SqlCardData,), {'_formdef': self, '_table_name': table_name}
             )
-            actions = sql.do_formdef_tables(self)
         else:
             cls = types.ClassType(
                 self.data_class_name,
                 (CardData,),
                 {'_names': 'card-%s' % self.internal_identifier, '_formdef': self},
             )
-            actions = []
         setattr(sys.modules['carddef'], self.data_class_name, cls)
         setattr(sys.modules['wcs.carddef'], self.data_class_name, cls)
 
-        if actions:
-            for action in actions:
-                getattr(cls, action)()
-
         return cls
 
     @classmethod
@@ -151,9 +145,9 @@ class CardDef(FormDef):
                 return True
         return False
 
-    def store(self, comment=None):
+    def store(self, comment=None, *args, **kwargs):
         self.roles = self.backoffice_submission_roles
-        return super().store(comment=comment)
+        return super().store(comment=comment, *args, **kwargs)
 
     @classmethod
     def get_carddefs_as_data_source(cls):
diff --git a/wcs/formdef.py b/wcs/formdef.py
index 71f524164..26170b1c9 100644
--- a/wcs/formdef.py
+++ b/wcs/formdef.py
@@ -312,21 +312,15 @@ class FormDef(StorableObject):
             cls = types.ClassType(
                 self.data_class_name, (sql.SqlFormData,), {'_formdef': self, '_table_name': table_name}
             )
-            actions = sql.do_formdef_tables(self)
         else:
             cls = types.ClassType(
                 self.data_class_name,
                 (FormData,),
                 {'_names': 'form-%s' % self.internal_identifier, '_formdef': self},
             )
-            actions = []
         setattr(sys.modules['formdef'], self.data_class_name, cls)
         setattr(sys.modules['wcs.formdef'], self.data_class_name, cls)
 
-        if actions:
-            for action in actions:
-                getattr(cls, action)()
-
         return cls
 
     def get_new_field_id(self):
@@ -408,6 +402,7 @@ class FormDef(StorableObject):
         new_internal_identifier = self.get_new_internal_identifier()
         if not self.internal_identifier:
             self.internal_identifier = new_internal_identifier
+        object_only = kwargs.pop('object_only', False)
         if new_internal_identifier != self.internal_identifier:
             # title changed, internal identifier will be changed only if
             # the formdef is currently being imported (self.id is None)
@@ -415,14 +410,26 @@ class FormDef(StorableObject):
             if self.id is None or self.data_class().count() == 0:
                 self.internal_identifier = new_internal_identifier
         StorableObject.store(self, *args, **kwargs)
+        if object_only:
+            return
         if get_publisher().snapshot_class:
             get_publisher().snapshot_class.snap(instance=self, comment=comment)
-        if get_publisher().is_using_postgresql():
-            from . import sql
 
-            sql.do_formdef_tables(self, rebuild_views=True, rebuild_global_views=True)
+        self.update_storage()
         self.store_related_custom_views()
 
+    def update_storage(self):
+        if not get_publisher().is_using_postgresql():
+            return
+
+        from . import sql
+
+        actions = sql.do_formdef_tables(self, rebuild_views=True, rebuild_global_views=True)
+        if actions:
+            cls = self.data_class()
+            for action in actions:
+                getattr(cls, action)()
+
     def store_related_custom_views(self):
         for view in getattr(self, '_custom_views', []):
             view.formdef = self
@@ -434,12 +441,6 @@ class FormDef(StorableObject):
     def get_widget_fields(self):
         return [field for field in self.fields or [] if isinstance(field, fields.WidgetField)]
 
-    def rebuild(self):
-        if get_publisher().is_using_postgresql():
-            from . import sql
-
-            sql.do_formdef_tables(self, rebuild_views=True, rebuild_global_views=True)
-
     @property
     def default_digest_template(self):
         return (self.digest_templates or {}).get('default')
diff --git a/wcs/sql.py b/wcs/sql.py
index a535acb7c..13a418021 100644
--- a/wcs/sql.py
+++ b/wcs/sql.py
@@ -424,7 +424,7 @@ def get_formdef_table_name(formdef):
         formdef.id,
         get_name_as_sql_identifier(formdef.url_name)[:30],
     )
-    formdef.store()
+    formdef.store(object_only=True)
     return formdef.table_name
 
 
diff --git a/wcs/workflows.py b/wcs/workflows.py
index fd79a7703..697e20f38 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -531,9 +531,9 @@ class Workflow(StorableObject):
                 self.formdefs(ignore_migration=True, order_by='id'),
                 self.carddefs(ignore_migration=True, order_by='id'),
             ):
-                form.data_class().rebuild_security()
                 if must_update:
-                    form.rebuild()
+                    form.update_storage()
+                form.data_class().rebuild_security()
 
         if get_response():
             get_response().add_after_job(_('Reindexing cards and forms after workflow change'), update)
-- 
2.33.0

