]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Change model uniqueness from name to name+owner
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 3 Mar 2023 19:43:34 +0000 (11:43 -0800)
committershamoon <4887959+shamoon@users.noreply.github.com>
Thu, 9 Mar 2023 03:07:32 +0000 (19:07 -0800)
src/documents/migrations/1033_alter_documenttype_options_alter_tag_options_and_more.py [new file with mode: 0644]
src/documents/models.py
src/documents/serialisers.py

diff --git a/src/documents/migrations/1033_alter_documenttype_options_alter_tag_options_and_more.py b/src/documents/migrations/1033_alter_documenttype_options_alter_tag_options_and_more.py
new file mode 100644 (file)
index 0000000..543f3a4
--- /dev/null
@@ -0,0 +1,107 @@
+# Generated by Django 4.1.5 on 2023-03-04 22:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("documents", "1032_alter_correspondent_matching_algorithm_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name="documenttype",
+            options={
+                "ordering": ("name",),
+                "verbose_name": "document type",
+                "verbose_name_plural": "document types",
+            },
+        ),
+        migrations.AlterModelOptions(
+            name="tag",
+            options={
+                "ordering": ("name",),
+                "verbose_name": "tag",
+                "verbose_name_plural": "tags",
+            },
+        ),
+        migrations.AlterField(
+            model_name="correspondent",
+            name="name",
+            field=models.CharField(max_length=128, verbose_name="name"),
+        ),
+        migrations.AlterField(
+            model_name="documenttype",
+            name="name",
+            field=models.CharField(max_length=128, verbose_name="name"),
+        ),
+        migrations.AlterField(
+            model_name="storagepath",
+            name="name",
+            field=models.CharField(max_length=128, verbose_name="name"),
+        ),
+        migrations.AlterField(
+            model_name="tag",
+            name="name",
+            field=models.CharField(max_length=128, verbose_name="name"),
+        ),
+        migrations.AddConstraint(
+            model_name="correspondent",
+            constraint=models.UniqueConstraint(
+                fields=("name", "owner"),
+                name="documents_correspondent_unique_name_owner",
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="correspondent",
+            constraint=models.UniqueConstraint(
+                condition=models.Q(("owner__isnull", True)),
+                fields=("name",),
+                name="documents_correspondent_name_uniq",
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="documenttype",
+            constraint=models.UniqueConstraint(
+                fields=("name", "owner"),
+                name="documents_documenttype_unique_name_owner",
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="documenttype",
+            constraint=models.UniqueConstraint(
+                condition=models.Q(("owner__isnull", True)),
+                fields=("name",),
+                name="documents_documenttype_name_uniq",
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="storagepath",
+            constraint=models.UniqueConstraint(
+                fields=("name", "owner"), name="documents_storagepath_unique_name_owner"
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="storagepath",
+            constraint=models.UniqueConstraint(
+                condition=models.Q(("owner__isnull", True)),
+                fields=("name",),
+                name="documents_storagepath_name_uniq",
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="tag",
+            constraint=models.UniqueConstraint(
+                fields=("name", "owner"), name="documents_tag_unique_name_owner"
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name="tag",
+            constraint=models.UniqueConstraint(
+                condition=models.Q(("owner__isnull", True)),
+                fields=("name",),
+                name="documents_tag_name_uniq",
+            ),
+        ),
+    ]
index 68fba37b9c67409558d5b17afc5479adb840c41b..303abe7303ea03cb7e83889fd67d64814661e15f 100644 (file)
@@ -23,7 +23,20 @@ ALL_STATES = sorted(states.ALL_STATES)
 TASK_STATE_CHOICES = sorted(zip(ALL_STATES, ALL_STATES))
 
 
-class MatchingModel(models.Model):
+class ModelWithOwner(models.Model):
+    owner = models.ForeignKey(
+        User,
+        blank=True,
+        null=True,
+        on_delete=models.SET_NULL,
+        verbose_name=_("owner"),
+    )
+
+    class Meta:
+        abstract = True
+
+
+class MatchingModel(ModelWithOwner):
 
     MATCH_NONE = 0
     MATCH_ANY = 1
@@ -43,7 +56,7 @@ class MatchingModel(models.Model):
         (MATCH_AUTO, _("Automatic")),
     )
 
-    name = models.CharField(_("name"), max_length=128, unique=True)
+    name = models.CharField(_("name"), max_length=128)
 
     match = models.CharField(_("match"), max_length=256, blank=True)
 
@@ -58,32 +71,29 @@ class MatchingModel(models.Model):
     class Meta:
         abstract = True
         ordering = ("name",)
+        constraints = [
+            models.UniqueConstraint(
+                fields=["name", "owner"],
+                name="%(app_label)s_%(class)s_unique_name_owner",
+            ),
+            models.UniqueConstraint(
+                name="%(app_label)s_%(class)s_name_uniq",
+                fields=["name"],
+                condition=models.Q(owner__isnull=True),
+            ),
+        ]
 
     def __str__(self):
         return self.name
 
 
-class ModelWithOwner(models.Model):
-    owner = models.ForeignKey(
-        User,
-        blank=True,
-        null=True,
-        on_delete=models.SET_NULL,
-        verbose_name=_("owner"),
-    )
-
-    class Meta:
-        abstract = True
-
-
-class Correspondent(MatchingModel, ModelWithOwner):
-    class Meta:
-        ordering = ("name",)
+class Correspondent(MatchingModel):
+    class Meta(MatchingModel.Meta):
         verbose_name = _("correspondent")
         verbose_name_plural = _("correspondents")
 
 
-class Tag(MatchingModel, ModelWithOwner):
+class Tag(MatchingModel):
 
     color = models.CharField(_("color"), max_length=7, default="#a6cee3")
 
@@ -96,25 +106,24 @@ class Tag(MatchingModel, ModelWithOwner):
         ),
     )
 
-    class Meta:
+    class Meta(MatchingModel.Meta):
         verbose_name = _("tag")
         verbose_name_plural = _("tags")
 
 
-class DocumentType(MatchingModel, ModelWithOwner):
-    class Meta:
+class DocumentType(MatchingModel):
+    class Meta(MatchingModel.Meta):
         verbose_name = _("document type")
         verbose_name_plural = _("document types")
 
 
-class StoragePath(MatchingModel, ModelWithOwner):
+class StoragePath(MatchingModel):
     path = models.CharField(
         _("path"),
         max_length=512,
     )
 
-    class Meta:
-        ordering = ("name",)
+    class Meta(MatchingModel.Meta):
         verbose_name = _("storage path")
         verbose_name_plural = _("storage paths")
 
index e61c0bd977e74988ece28d880a1152012db66434..6fa4cd065ab40ccf02f17c4447cce365d96f59a2 100644 (file)
@@ -186,6 +186,18 @@ class OwnedObjectSerializer(serializers.ModelSerializer, SetPermissionsMixin):
     def update(self, instance, validated_data):
         if "set_permissions" in validated_data:
             self._set_permissions(validated_data["set_permissions"], instance)
+        if "owner" in validated_data and "name" in self.Meta.fields:
+            name = validated_data["name"] if "name" in validated_data else instance.name
+            print(name)
+            not_unique = (
+                self.Meta.model.objects.exclude(pk=instance.pk)
+                .filter(owner=validated_data["owner"], name=name)
+                .exists()
+            )
+            if not_unique:
+                raise serializers.ValidationError(
+                    "Object violates owner / name unique constraint",
+                )
         return super().update(instance, validated_data)