Make them owned, duh

Update 0028_ocrtemplate_ocrtemplatezone.py
This commit is contained in:
shamoon committed 2026-10-20 11:15:30 -07:00
1 parent 77a7fb40ec
commit 4ff2cb9c72
5 files changed
+122 -10

No files matched your search

@@ -3,6 +3,7 @@
import django.core.validators
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations
from django.db import models
@@ -26,6 +27,17 @@ class Migration(migrations.Migration):
),
),
("name", models.CharField(max_length=128, verbose_name="name")),
(
"owner",
models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name="owner",
),
),
(
"source_width",
models.PositiveIntegerField(
+1 -1
View File
@@ -2151,7 +2151,7 @@ class WorkflowRun(SoftDeleteModel):
return f"WorkflowRun of {self.workflow} at {self.run_at} on {self.document}"
class OcrTemplate(models.Model):
class OcrTemplate(ModelWithOwner):
"""
Defines a set of OCR extraction zones for a specific document type.
+7 -6
View File
@@ -3781,7 +3781,7 @@ class OcrTemplateZoneSerializer(serializers.ModelSerializer):
return value
class OcrTemplateSerializer(serializers.ModelSerializer):
class OcrTemplateSerializer(OwnedObjectSerializer):
zones = OcrTemplateZoneSerializer(many=True, required=False)
class Meta:
@@ -3798,6 +3798,10 @@ class OcrTemplateSerializer(serializers.ModelSerializer):
"created",
"updated",
"zones",
"owner",
"permissions",
"user_can_change",
"set_permissions",
]
read_only_fields = ["created", "updated"]
@@ -3842,17 +3846,14 @@ class OcrTemplateSerializer(serializers.ModelSerializer):
def create(self, validated_data):
zones_data = validated_data.pop("zones", [])
template = OcrTemplate.objects.create(**validated_data)
template = super().create(validated_data)
for zone_data in zones_data:
OcrTemplateZone.objects.create(template=template, **zone_data)
return template
def update(self, instance, validated_data):
zones_data = validated_data.pop("zones", None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
instance = super().update(instance, validated_data)
if zones_data is not None:
# Replace all zones with the new set
@@ -109,6 +109,98 @@ class TestOcrTemplatesAPI(DirectoriesMixin, APITestCase):
self.assertEqual(OcrTemplate.objects.count(), 1)
self.assertEqual(OcrTemplateZone.objects.count(), 1)
def test_create_template_sets_owner(self):
"""
GIVEN:
- A user creating an OCR template
WHEN:
- API request to create it without an owner
THEN:
- The requesting user owns the template
"""
response = self.client.post(
self.ENDPOINT,
json.dumps(self._make_template_data()),
content_type="application/json",
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(OcrTemplate.objects.get().owner, self.user)
def test_list_only_shows_permitted_templates(self):
"""
GIVEN:
- Templates that are unowned, owned by the user, owned by another
user, and owned by another user but shared with the user
WHEN:
- The user lists OCR templates
THEN:
- Only the unowned, owned and shared templates are returned
"""
other = User.objects.create_user(username="other")
user = User.objects.create_user(username="template_viewer")
user.user_permissions.add(Permission.objects.get(codename="view_ocrtemplate"))
def template(name, owner=None):
return OcrTemplate.objects.create(
name=name,
document_type=self.doc_type,
source_width=1000,
source_height=1000,
owner=owner,
)
template("Unowned")
template("Mine", owner=user)
template("Private", owner=other)
grant_object(user, template("Shared", owner=other), "view_ocrtemplate")
self.client.force_authenticate(user=user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertCountEqual(
[t["name"] for t in response.json()["results"]],
["Unowned", "Mine", "Shared"],
)
def test_cannot_change_another_users_template(self):
"""
GIVEN:
- A template owned by another user
WHEN:
- A user with global change permission tries to update it
THEN:
- The update is refused until the user is granted change on it
"""
other = User.objects.create_user(username="other")
user = User.objects.create_user(username="template_editor")
user.user_permissions.add(
*Permission.objects.filter(
codename__in=["view_ocrtemplate", "change_ocrtemplate"],
),
)
template = OcrTemplate.objects.create(
name="Private",
document_type=self.doc_type,
source_width=1000,
source_height=1000,
owner=other,
)
grant_object(user, template, "view_ocrtemplate")
self.client.force_authenticate(user=user)
url = f"{self.ENDPOINT}{template.pk}/"
response = self.client.patch(url, {"name": "Renamed"}, format="json")
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
grant_object(user, template, "change_ocrtemplate")
response = self.client.patch(url, {"name": "Renamed"}, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
template.refresh_from_db()
self.assertEqual(template.name, "Renamed")
self.assertEqual(template.owner, other)
def test_create_template_multiple_zones(self):
"""
GIVEN:
+10 -3
View File
@@ -5835,11 +5835,13 @@ def serve_logo(request: HttpRequest, filename: str | None = None) -> FileRespons
)
class OcrTemplateViewSet(ModelViewSet):
class OcrTemplateViewSet(BulkPermissionMixin, PassUserMixin, ModelViewSet[OcrTemplate]):
"""CRUD for OCR templates with zone definitions."""
model = OcrTemplate
queryset = (
OcrTemplate.objects.all()
OcrTemplate.objects.select_related("owner")
.prefetch_related(
"zones",
"zones__custom_field",
@@ -5847,8 +5849,13 @@ class OcrTemplateViewSet(ModelViewSet):
.order_by("name")
)
serializer_class = OcrTemplateSerializer
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
pagination_class = StandardPagination
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
filter_backends = (
OrderingFilter,
PermittedObjectsFilter,
)
ordering_fields = ("name",)
@action(
detail=False,