Repository: e-valuation/EvaP

Issue:
Migrate Evaluation.state in LogEntries
In 37508eb2c426, the `Evaluation.state` was turned into an `FSMIntegerField`. However, the migration didn't update the evaluations' log entries. This leads to errors in `evaluation.models.transform_log_action` when rendering log messages because old entries hold strings (e.g. `"in_evaluation"`) which results in a `KeyError` for `STATE_STR_CONVERSION` that expects a number (e.g. `State.IN_EVALUATION`).


Discussion:

Resolving patch:
diff --git a/evap/evaluation/migrations/0123_evaluation_state_fsm_int.py b/evap/evaluation/migrations/0123_evaluation_state_fsm_int.py
--- a/evap/evaluation/migrations/0123_evaluation_state_fsm_int.py
+++ b/evap/evaluation/migrations/0123_evaluation_state_fsm_int.py
@@ -1,5 +1,4 @@
 from django.db import migrations
-import django_fsm
 
 
 # as defined in the Evaluation model
@@ -24,28 +23,52 @@ class State:
     "reviewed": State.REVIEWED,
     "published": State.PUBLISHED,
 }
+REV_CONVERSION = {val: key for key, val in CONVERSION.items()}
 
 
-def str_to_int(apps, _schema_editor):
+def model_str_to_int(apps, _schema_editor):
     Evaluation = apps.get_model("evaluation", "Evaluation")
     for string_type, int_type in CONVERSION.items():
         Evaluation.objects.filter(state=string_type).update(int_state=int_type)
 
 
-def int_to_str(apps, _schema_editor):
+def model_int_to_str(apps, _schema_editor):
     Evaluation = apps.get_model("evaluation", "Evaluation")
     for string_type, int_type in CONVERSION.items():
         Evaluation.objects.filter(int_state=int_type).update(state=string_type)
 
 
+def logentries_str_to_int(apps, _schema_editor):
+    LogEntry = apps.get_model("evaluation", "LogEntry")
+    for entry in LogEntry.objects.filter(content_type__app_label="evaluation", content_type__model="evaluation"):
+        if "state" in entry.data:
+            for key in entry.data["state"]:
+                entry.data["state"][key] = [
+                    CONVERSION[val] if val in CONVERSION else val for val in entry.data["state"][key]
+                ]
+            entry.save()
+
+
+def logentries_int_to_str(apps, _schema_editor):
+    LogEntry = apps.get_model("evaluation", "LogEntry")
+    for entry in LogEntry.objects.filter(content_type__app_label="evaluation", content_type__model="evaluation"):
+        if "state" in entry.data:
+            for key in entry.data["state"]:
+                entry.data["state"][key] = [
+                    REV_CONVERSION[val] if val in REV_CONVERSION else val for val in entry.data["state"][key]
+                ]
+            entry.save()
+
+
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('evaluation', '0122_prepare_evaluation_state_fsm_int'),
+        ("evaluation", "0122_prepare_evaluation_state_fsm_int"),
     ]
 
     operations = [
-        migrations.RunPython(str_to_int, int_to_str),
+        migrations.RunPython(model_str_to_int, model_int_to_str),
+        migrations.RunPython(logentries_str_to_int, logentries_int_to_str),
         migrations.RemoveField(
             model_name="evaluation",
             name="state",
diff --git a/evap/evaluation/migrations/0127_fix_logentry_types.py b/evap/evaluation/migrations/0127_fix_logentry_types.py
new file mode 100644
--- /dev/null
+++ b/evap/evaluation/migrations/0127_fix_logentry_types.py
@@ -0,0 +1,19 @@
+import importlib
+from django.db import migrations
+
+original_migration_module = importlib.import_module("evap.evaluation.migrations.0123_evaluation_state_fsm_int")
+
+
+class Migration(migrations.Migration):
+    """
+    Initially, we forgot to migrate logentries in 0123, so this migration cleans this up.
+    Note that 0123 is now modified to also take care of the logentries in the first place.
+    """
+
+    dependencies = [
+        ("evaluation", "0126_add_textanswer_review_email_template"),
+    ]
+
+    operations = [
+        migrations.RunPython(original_migration_module.logentries_str_to_int, migrations.RunPython.noop),
+    ]


Test patch: