From 966090d91ef1388152a7dda70f5bd9032e2f5c22 Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Mon, 9 Oct 2023 14:07:13 +0200 Subject: [PATCH] :hammer: [#3527] Add duplicate form steps detection script Backport-of: #3528 --- bin/check_non_unique_steps.py | 72 +++++++++++++++++++++++++ src/openforms/upgrades/upgrade_paths.py | 6 ++- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100755 bin/check_non_unique_steps.py diff --git a/bin/check_non_unique_steps.py b/bin/check_non_unique_steps.py new file mode 100755 index 0000000000..7208fe8dd9 --- /dev/null +++ b/bin/check_non_unique_steps.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +import sys +from pathlib import Path + +import django + +from tabulate import tabulate + +SRC_DIR = Path(__file__).parent.parent / "src" +sys.path.insert(0, str(SRC_DIR.resolve())) + + +def check_non_unique_steps() -> bool: + from django.db.models import Count + + from openforms.forms.models import Form, FormDefinition, FormStep + + # query for form definitions used multiple times in a form + qs = ( + FormStep.objects.values("form", "form_definition") + .annotate(occurrences=Count("form_definition")) + .filter(occurrences__gt=1) + .order_by() # reset ordering (implicitly added by django-ordered-model) + ) + num = qs.count() + if not num: + print("No forms found with duplicated form steps.") + return True + + # report which forms have issues + forms = Form.objects.filter(pk__in=qs.values_list("form")).in_bulk() + form_definitions = FormDefinition.objects.filter( + pk__in=qs.values_list("form_definition") + ).in_bulk() + + duplicates = [] + for item in qs: + form = forms[item["form"]] + form_definition = form_definitions[item["form_definition"]] + + duplicates.append( + [ + form.admin_name, + form_definition.admin_name, + item["occurrences"], + ] + ) + + print("Found forms with duplicated steps.") + print("") + print( + tabulate( + duplicates, + headers=("Form", "Form step", "Occurrences"), + ) + ) + + return False + + +def main(skip_setup=False) -> bool: + from openforms.setup import setup_env + + if not skip_setup: + setup_env() + django.setup() + + return check_non_unique_steps() + + +if __name__ == "__main__": + main() diff --git a/src/openforms/upgrades/upgrade_paths.py b/src/openforms/upgrades/upgrade_paths.py index 45a9ec6e21..9c9e444352 100644 --- a/src/openforms/upgrades/upgrade_paths.py +++ b/src/openforms/upgrades/upgrade_paths.py @@ -79,7 +79,11 @@ def run_checks(self) -> bool: "2.3": UpgradeConstraint( valid_ranges={ VersionRange(minimum="2.1.3"), - } + }, + scripts=( + # run detection to prevent crashes, see #3527 + "check_non_unique_steps", + ), ), "2.2": UpgradeConstraint( valid_ranges={