From b0d76f9030ffa798880a3b595d3a9eaa473b34ef Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Mon, 30 Sep 2024 12:22:34 +0200
Subject: [PATCH] Add migrations for fixing unique constraints

---
 .../0018_fix_unique_constraints_1.py          | 98 +++++++++++++++++++
 .../0019_fix_unique_constraints_2.py          | 53 ++++++++++
 aleksis/apps/alsijil/models.py                |  8 +-
 3 files changed, 155 insertions(+), 4 deletions(-)
 create mode 100644 aleksis/apps/alsijil/migrations/0018_fix_unique_constraints_1.py
 create mode 100644 aleksis/apps/alsijil/migrations/0019_fix_unique_constraints_2.py

diff --git a/aleksis/apps/alsijil/migrations/0018_fix_unique_constraints_1.py b/aleksis/apps/alsijil/migrations/0018_fix_unique_constraints_1.py
new file mode 100644
index 000000000..030379f36
--- /dev/null
+++ b/aleksis/apps/alsijil/migrations/0018_fix_unique_constraints_1.py
@@ -0,0 +1,98 @@
+# Generated by Django 4.2.16 on 2024-09-26 14:54
+
+from django.db import migrations, models
+from reversion.models import Version
+from reversion import  create_revision
+
+def fix_constraints(apps, schema_editor):
+    LessonDocumentation = apps.get_model("alsijil", "LessonDocumentation")
+    PersonalNote = apps.get_model("alsijil", "PersonalNote")
+
+    with create_revision():
+        personal_notes = PersonalNote.objects.filter(extra_lesson_id__isnull=False).values("extra_lesson_id", "person_id", "week", "year").annotate(count=models.Count("id")).filter(count__gt=1)
+
+
+        for personal_note in personal_notes:
+            affected_entries = PersonalNote.objects.filter(extra_lesson_id=personal_note["extra_lesson_id"], person_id=personal_note["person_id"])
+            current_date = None
+            newest = None
+            for affected_entry in affected_entries:
+                versions = Version.objects.get_for_object(affected_entry)
+                if not versions:
+                    if not newest:
+                        newest = affected_entry
+                    continue
+                version = versions[0]
+                if not current_date or version.revision.date_created > current_date:
+                    current_date = version.revision.date_created
+                    newest = affected_entry
+
+            affected_entries.exclude(pk=newest.pk).delete()
+
+        personal_notes = PersonalNote.objects.filter(event_id__isnull=False).values("event_id", "person_id", "week", "year").annotate(count=models.Count("id")).filter(count__gt=1)
+
+        for personal_note in personal_notes:
+            affected_entries = PersonalNote.objects.filter(event_id=personal_note["event_id"], person_id=personal_note["person_id"])
+            current_date = None
+            newest = None
+            for affected_entry in affected_entries:
+                versions = Version.objects.get_for_object(affected_entry)
+                if not versions:
+                    if not newest:
+                        newest = affected_entry
+                    continue
+                version = versions[0]
+                if not current_date or version.revision.date_created > current_date:
+                    current_date = version.revision.date_created
+                    newest = affected_entry
+
+            affected_entries.exclude(pk=newest.pk).delete()
+
+        lesson_documentations = LessonDocumentation.objects.filter(extra_lesson_id__isnull=False).values("extra_lesson_id", "week", "year").annotate(count=models.Count("id")).filter(count__gt=1)
+
+        for lesson_documentation in lesson_documentations:
+            affected_entries = LessonDocumentation.objects.filter(extra_lesson_id=lesson_documentation["extra_lesson_id"])
+            current_date = None
+            newest = None
+            for affected_entry in affected_entries:
+                versions = Version.objects.get_for_object(affected_entry)
+                if not versions:
+                    if not newest:
+                        newest = affected_entry
+                    continue
+                version = versions[0]
+                if not current_date or version.revision.date_created > current_date:
+                    current_date = version.revision.date_created
+                    newest = affected_entry
+
+            affected_entries.exclude(pk=newest.pk).delete()
+
+
+        lesson_documentations = LessonDocumentation.objects.filter(event_id__isnull=False).values("event_id", "week", "year").annotate(count=models.Count("id")).filter(count__gt=1)
+
+        for lesson_documentation in lesson_documentations:
+            affected_entries = LessonDocumentation.objects.filter(event_id=lesson_documentation["event_id"])
+            current_date = None
+            newest = None
+            for affected_entry in affected_entries:
+                versions = Version.objects.get_for_object(affected_entry)
+                if not versions:
+                    if not newest:
+                        newest = affected_entry
+                    continue
+                version = versions[0]
+                if not current_date or version.revision.date_created > current_date:
+                    current_date = version.revision.date_created
+                    newest = affected_entry
+
+            affected_entries.exclude(pk=newest.pk).delete()
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("alsijil", "0017_rename_late_to_tardiness"),
+    ]
+
+    operations = [
+        migrations.RunPython(fix_constraints),
+    ]
diff --git a/aleksis/apps/alsijil/migrations/0019_fix_unique_constraints_2.py b/aleksis/apps/alsijil/migrations/0019_fix_unique_constraints_2.py
new file mode 100644
index 000000000..e20d5e139
--- /dev/null
+++ b/aleksis/apps/alsijil/migrations/0019_fix_unique_constraints_2.py
@@ -0,0 +1,53 @@
+# Generated by Django 4.2.16 on 2024-09-26 14:54
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("alsijil", "0018_fix_unique_constraints_1"),
+    ]
+
+    operations = [
+        migrations.RemoveConstraint(
+            model_name="lessondocumentation",
+            name="unique_documentation_per_ev",
+        ),
+        migrations.RemoveConstraint(
+            model_name="lessondocumentation",
+            name="unique_documentation_per_el",
+        ),
+        migrations.RemoveConstraint(
+            model_name="personalnote",
+            name="unique_note_per_ev",
+        ),
+        migrations.RemoveConstraint(
+            model_name="personalnote",
+            name="unique_note_per_el",
+        ),
+        migrations.AddConstraint(
+            model_name="lessondocumentation",
+            constraint=models.UniqueConstraint(
+                fields=("event",), name="unique_documentation_per_ev"
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="lessondocumentation",
+            constraint=models.UniqueConstraint(
+                fields=("extra_lesson",), name="unique_documentation_per_el"
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="personalnote",
+            constraint=models.UniqueConstraint(
+                fields=("event", "person"), name="unique_note_per_ev"
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="personalnote",
+            constraint=models.UniqueConstraint(
+                fields=("extra_lesson", "person"), name="unique_note_per_el"
+            ),
+        ),
+    ]
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index c9a964714..1950330ca 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -310,11 +310,11 @@ class PersonalNote(RegisterObjectRelatedMixin, ExtensibleModel):
                 name="unique_note_per_lp",
             ),
             models.UniqueConstraint(
-                fields=("week", "year", "event", "person"),
+                fields=("event", "person"),
                 name="unique_note_per_ev",
             ),
             models.UniqueConstraint(
-                fields=("week", "year", "extra_lesson", "person"),
+                fields=("extra_lesson", "person"),
                 name="unique_note_per_el",
             ),
         ]
@@ -413,11 +413,11 @@ class LessonDocumentation(RegisterObjectRelatedMixin, ExtensibleModel):
                 name="unique_documentation_per_lp",
             ),
             models.UniqueConstraint(
-                fields=("week", "year", "event"),
+                fields=("event",),
                 name="unique_documentation_per_ev",
             ),
             models.UniqueConstraint(
-                fields=("week", "year", "extra_lesson"),
+                fields=("extra_lesson",),
                 name="unique_documentation_per_el",
             ),
         ]
-- 
GitLab