Save some not working stuff
This commit is contained in:
parent
8605907f6f
commit
d9526ea32f
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.2.5 on 2023-10-25 13:49
|
# Generated by Django 4.2.5 on 2023-10-28 02:54
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
@ -43,8 +43,8 @@ class Migration(migrations.Migration):
|
|||||||
("url", "URL"),
|
("url", "URL"),
|
||||||
("date", "Date"),
|
("date", "Date"),
|
||||||
("boolean", "Boolean"),
|
("boolean", "Boolean"),
|
||||||
|
("integer", "Integer"),
|
||||||
],
|
],
|
||||||
default="string",
|
|
||||||
max_length=50,
|
max_length=50,
|
||||||
verbose_name="data type",
|
verbose_name="data type",
|
||||||
),
|
),
|
||||||
@ -56,54 +56,6 @@ class Migration(migrations.Migration):
|
|||||||
"ordering": ("created",),
|
"ordering": ("created",),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
|
||||||
name="CustomFieldBoolean",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.AutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("value", models.BooleanField()),
|
|
||||||
(
|
|
||||||
"parent",
|
|
||||||
models.OneToOneField(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
related_name="boolean",
|
|
||||||
to="documents.customfieldinstance",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="CustomFieldDate",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.AutoField(
|
|
||||||
auto_created=True,
|
|
||||||
primary_key=True,
|
|
||||||
serialize=False,
|
|
||||||
verbose_name="ID",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("value", models.DateField()),
|
|
||||||
(
|
|
||||||
"parent",
|
|
||||||
models.OneToOneField(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
parent_link=True,
|
|
||||||
related_name="date",
|
|
||||||
to="documents.customfieldinstance",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="CustomFieldInstance",
|
name="CustomFieldInstance",
|
||||||
fields=[
|
fields=[
|
||||||
@ -157,6 +109,78 @@ class Migration(migrations.Migration):
|
|||||||
"ordering": ("created",),
|
"ordering": ("created",),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="CustomFieldBoolean",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("value", models.BooleanField()),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
related_name="boolean",
|
||||||
|
to="documents.customfieldinstance",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="CustomFieldDate",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("value", models.DateField()),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
related_name="date",
|
||||||
|
to="documents.customfieldinstance",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="CustomFieldInteger",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("value", models.IntegerField()),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.OneToOneField(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
related_name="integer",
|
||||||
|
to="documents.customfieldinstance",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="CustomFieldShortText",
|
name="CustomFieldShortText",
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -895,6 +895,7 @@ class CustomField(models.Model):
|
|||||||
URL = ("url", _("URL"))
|
URL = ("url", _("URL"))
|
||||||
DATE = ("date", _("Date"))
|
DATE = ("date", _("Date"))
|
||||||
BOOL = ("boolean"), _("Boolean")
|
BOOL = ("boolean"), _("Boolean")
|
||||||
|
INT = ("integer", _("Integer"))
|
||||||
|
|
||||||
created = models.DateTimeField(
|
created = models.DateTimeField(
|
||||||
_("created"),
|
_("created"),
|
||||||
@ -908,7 +909,6 @@ class CustomField(models.Model):
|
|||||||
_("data type"),
|
_("data type"),
|
||||||
max_length=50,
|
max_length=50,
|
||||||
choices=FieldDataType.choices,
|
choices=FieldDataType.choices,
|
||||||
default=FieldDataType.STRING,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -969,6 +969,8 @@ class CustomFieldInstance(ModelWithOwner):
|
|||||||
return self.date.value
|
return self.date.value
|
||||||
elif self.field.data_type == CustomField.FieldDataType.BOOL:
|
elif self.field.data_type == CustomField.FieldDataType.BOOL:
|
||||||
return self.boolean.value
|
return self.boolean.value
|
||||||
|
elif self.field.data_type == CustomField.FieldDataType.INT:
|
||||||
|
return self.integer.value
|
||||||
raise NotImplementedError(self.field.data_type)
|
raise NotImplementedError(self.field.data_type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -984,6 +986,8 @@ class CustomFieldInstance(ModelWithOwner):
|
|||||||
return CustomFieldDate
|
return CustomFieldDate
|
||||||
elif self.field.data_type == CustomField.FieldDataType.BOOL:
|
elif self.field.data_type == CustomField.FieldDataType.BOOL:
|
||||||
return CustomFieldBoolean
|
return CustomFieldBoolean
|
||||||
|
elif self.field.data_type == CustomField.FieldDataType.INT:
|
||||||
|
return CustomFieldInteger
|
||||||
raise NotImplementedError(self.field.data_type)
|
raise NotImplementedError(self.field.data_type)
|
||||||
|
|
||||||
def to_json(self) -> dict[str, str]:
|
def to_json(self) -> dict[str, str]:
|
||||||
@ -1077,3 +1081,20 @@ class CustomFieldDate(models.Model):
|
|||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.value}"
|
return f"{self.value}"
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldInteger(models.Model):
|
||||||
|
"""
|
||||||
|
Data storage for a date custom field
|
||||||
|
"""
|
||||||
|
|
||||||
|
value = models.IntegerField()
|
||||||
|
parent = models.OneToOneField(
|
||||||
|
CustomFieldInstance,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="integer",
|
||||||
|
parent_link=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.value}"
|
||||||
|
@ -396,6 +396,40 @@ class StoragePathField(serializers.PrimaryKeyRelatedField):
|
|||||||
return StoragePath.objects.all()
|
return StoragePath.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = CustomField
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"data_type",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldInstanceSerializer(serializers.ModelSerializer):
|
||||||
|
parent = CustomFieldSerializer()
|
||||||
|
value = SerializerMethodField()
|
||||||
|
|
||||||
|
def get_value(self, obj: CustomFieldInstance):
|
||||||
|
return obj.value
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
parent_data = validated_data.pop("parent")
|
||||||
|
parent = CustomField.objects.get(id=parent_data["id"])
|
||||||
|
instance = CustomFieldInstance.objects.create(parent=parent)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def update(self, instance: CustomFieldInstance):
|
||||||
|
return instance
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CustomFieldInstance
|
||||||
|
fields = [
|
||||||
|
"parent",
|
||||||
|
"value",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
|
class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
|
||||||
correspondent = CorrespondentField(allow_null=True)
|
correspondent = CorrespondentField(allow_null=True)
|
||||||
tags = TagsField(many=True)
|
tags = TagsField(many=True)
|
||||||
@ -406,6 +440,8 @@ class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
|
|||||||
archived_file_name = SerializerMethodField()
|
archived_file_name = SerializerMethodField()
|
||||||
created_date = serializers.DateField(required=False)
|
created_date = serializers.DateField(required=False)
|
||||||
|
|
||||||
|
custom_fields = CustomFieldInstanceSerializer(many=True, allow_null=True)
|
||||||
|
|
||||||
owner = serializers.PrimaryKeyRelatedField(
|
owner = serializers.PrimaryKeyRelatedField(
|
||||||
queryset=User.objects.all(),
|
queryset=User.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
@ -468,6 +504,7 @@ class DocumentSerializer(OwnedObjectSerializer, DynamicFieldsModelSerializer):
|
|||||||
"user_can_change",
|
"user_can_change",
|
||||||
"set_permissions",
|
"set_permissions",
|
||||||
"notes",
|
"notes",
|
||||||
|
"custom_fields",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -1092,13 +1129,3 @@ class ConsumptionTemplateSerializer(serializers.ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = CustomField
|
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldInstanceSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = CustomFieldInstance
|
|
||||||
|
82
src/documents/tests/test_api_custom_fields.py
Normal file
82
src/documents/tests/test_api_custom_fields.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from documents.models import CustomField
|
||||||
|
from documents.models import Document
|
||||||
|
from documents.tests.utils import DirectoriesMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestCustomField(DirectoriesMixin, APITestCase):
|
||||||
|
ENDPOINT = "/api/custom_fields/"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user = User.objects.create_superuser(username="temp_admin")
|
||||||
|
self.client.force_authenticate(user=self.user)
|
||||||
|
return super().setUp()
|
||||||
|
|
||||||
|
def test_create_custom_field(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Each of the supported data types is created
|
||||||
|
WHEN:
|
||||||
|
- API request to create custom metadata is made
|
||||||
|
THEN:
|
||||||
|
- the field is created
|
||||||
|
- the field returns the correct fields
|
||||||
|
"""
|
||||||
|
for field_type, name in [
|
||||||
|
("string", "Custom Text"),
|
||||||
|
("url", "Wikipedia Link"),
|
||||||
|
("date", "Invoiced Date"),
|
||||||
|
("integer", "Invoice #"),
|
||||||
|
]:
|
||||||
|
resp = self.client.post(
|
||||||
|
self.ENDPOINT,
|
||||||
|
data={
|
||||||
|
"data_type": field_type,
|
||||||
|
"name": name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
data = resp.json()
|
||||||
|
|
||||||
|
self.assertEqual(len(data), 3)
|
||||||
|
self.assertEqual(data["name"], name)
|
||||||
|
self.assertEqual(data["data_type"], field_type)
|
||||||
|
|
||||||
|
def test_create_custom_field_instance(self):
|
||||||
|
doc = Document.objects.create(
|
||||||
|
title="WOW",
|
||||||
|
content="the content",
|
||||||
|
checksum="123",
|
||||||
|
mime_type="application/pdf",
|
||||||
|
)
|
||||||
|
custom_field = CustomField.objects.create(
|
||||||
|
name="Test Custom Field",
|
||||||
|
data_type=CustomField.FieldDataType.STRING,
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = self.client.patch(
|
||||||
|
f"/api/documents/{doc.id}/",
|
||||||
|
data={
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"parent": {
|
||||||
|
"id": custom_field.id,
|
||||||
|
},
|
||||||
|
"value": "test value",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
doc.refresh_from_db()
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
for item in doc.custom_fields.all():
|
||||||
|
pprint(item)
|
||||||
|
self.assertFalse(True)
|
@ -1,291 +0,0 @@
|
|||||||
from datetime import timedelta
|
|
||||||
from unittest import mock
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
|
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.utils import timezone
|
|
||||||
from guardian.shortcuts import assign_perm
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.test import APITestCase
|
|
||||||
|
|
||||||
from documents.models import CustomMetadata
|
|
||||||
from documents.models import Document
|
|
||||||
from documents.tests.utils import DirectoriesMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestCustomMetadata(DirectoriesMixin, APITestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.user = User.objects.create_superuser(username="temp_admin")
|
|
||||||
self.client.force_authenticate(user=self.user)
|
|
||||||
return super().setUp()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def create_json_no_date(metadata: CustomMetadata):
|
|
||||||
"""
|
|
||||||
Small helper to remove the created datatime from the JSON
|
|
||||||
It doesn't matter to verify
|
|
||||||
"""
|
|
||||||
expected = metadata.to_json()
|
|
||||||
del expected["created"]
|
|
||||||
return expected
|
|
||||||
|
|
||||||
def test_get_existing_custom_metadata(self):
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- A document with 2 different metadata attached to it
|
|
||||||
WHEN:
|
|
||||||
- API request for document custom metadata is made
|
|
||||||
THEN:
|
|
||||||
- Both associated values are returned
|
|
||||||
"""
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom metadata on it! Neat",
|
|
||||||
)
|
|
||||||
|
|
||||||
metadata1 = CustomMetadata.objects.create(
|
|
||||||
data_type=CustomMetadata.DataType.STRING,
|
|
||||||
name="Invoice Number",
|
|
||||||
data="#123456",
|
|
||||||
document=doc,
|
|
||||||
user=self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
metadata2 = CustomMetadata.objects.create(
|
|
||||||
data_type=CustomMetadata.DataType.URL,
|
|
||||||
name="October 20th, 2023 On This Day",
|
|
||||||
data="https://en.wikipedia.org/wiki/Pope_Pius_XII",
|
|
||||||
document=doc,
|
|
||||||
user=self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
all_metadata = [metadata1, metadata2]
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
resp_data = response.json()
|
|
||||||
|
|
||||||
self.assertEqual(len(resp_data), 2)
|
|
||||||
|
|
||||||
for idx, resp_data in enumerate(reversed(resp_data)):
|
|
||||||
del resp_data["created"]
|
|
||||||
|
|
||||||
self.assertDictEqual(
|
|
||||||
resp_data,
|
|
||||||
self.create_json_no_date(all_metadata[idx]),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_create_custom_metadata(self):
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- Existing document
|
|
||||||
WHEN:
|
|
||||||
- API request is made to add 2 custom metadata fields
|
|
||||||
THEN:
|
|
||||||
- metadata objects are created and associated with document
|
|
||||||
- Document modified time is updated
|
|
||||||
"""
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom_metadata added",
|
|
||||||
created=timezone.now() - timedelta(days=1),
|
|
||||||
)
|
|
||||||
# set to yesterday
|
|
||||||
doc.modified = timezone.now() - timedelta(days=1)
|
|
||||||
self.assertEqual(doc.modified.day, (timezone.now() - timedelta(days=1)).day)
|
|
||||||
|
|
||||||
resp = self.client.post(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
data={"type": "string", "name": "Custom Field 1", "data": "Custom Data 1"},
|
|
||||||
)
|
|
||||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
resp_data = response.json()
|
|
||||||
|
|
||||||
self.assertEqual(len(resp_data), 1)
|
|
||||||
|
|
||||||
resp_data = resp_data[0]
|
|
||||||
|
|
||||||
self.assertEqual(resp_data["data"], "Custom Data 1")
|
|
||||||
|
|
||||||
doc = Document.objects.get(pk=doc.pk)
|
|
||||||
# modified was updated to today
|
|
||||||
self.assertEqual(doc.modified.day, timezone.now().day)
|
|
||||||
|
|
||||||
def test_custom_metadata_view_add_delete_permissions_aware(self):
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- Existing document owned by user2 but with granted view perms for user1
|
|
||||||
WHEN:
|
|
||||||
- API request is made by user1 to add a custom metadata
|
|
||||||
THEN:
|
|
||||||
- custom metadata is not created
|
|
||||||
"""
|
|
||||||
user1 = User.objects.create_user(username="test1")
|
|
||||||
user1.user_permissions.add(*Permission.objects.all())
|
|
||||||
user1.save()
|
|
||||||
|
|
||||||
user2 = User.objects.create_user(username="test2")
|
|
||||||
user2.save()
|
|
||||||
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom_metadata added",
|
|
||||||
)
|
|
||||||
doc.owner = user2
|
|
||||||
doc.save()
|
|
||||||
|
|
||||||
self.client.force_authenticate(user1)
|
|
||||||
|
|
||||||
resp = self.client.get(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
resp.content,
|
|
||||||
b"Insufficient permissions to view custom metadata",
|
|
||||||
)
|
|
||||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
|
||||||
|
|
||||||
assign_perm("view_document", user1, doc)
|
|
||||||
|
|
||||||
resp = self.client.post(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
data={"type": "string", "name": "Custom Field 1", "data": "Custom Data 1"},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
resp.content,
|
|
||||||
b"Insufficient permissions to create custom metadata",
|
|
||||||
)
|
|
||||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
|
||||||
|
|
||||||
metadata = CustomMetadata.objects.create(
|
|
||||||
data_type=CustomMetadata.DataType.STRING,
|
|
||||||
name="Invoice Number",
|
|
||||||
data="#123456",
|
|
||||||
document=doc,
|
|
||||||
user=self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.delete(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/?id={metadata.pk}",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
response.content,
|
|
||||||
b"Insufficient permissions to delete custom metadata",
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
|
||||||
|
|
||||||
def test_delete_custom_metadata(self):
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- Existing document, existing custom metadata
|
|
||||||
WHEN:
|
|
||||||
- API request is made to delete a custom metadata
|
|
||||||
THEN:
|
|
||||||
- custom metadata is deleted, document modified is updated
|
|
||||||
"""
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom metadata!",
|
|
||||||
created=timezone.now() - timedelta(days=1),
|
|
||||||
)
|
|
||||||
# set to yesterday
|
|
||||||
doc.modified = timezone.now() - timedelta(days=1)
|
|
||||||
self.assertEqual(doc.modified.day, (timezone.now() - timedelta(days=1)).day)
|
|
||||||
|
|
||||||
metadata = CustomMetadata.objects.create(
|
|
||||||
data_type=CustomMetadata.DataType.DATE,
|
|
||||||
name="Invoice Number",
|
|
||||||
data="2023-10-20",
|
|
||||||
document=doc,
|
|
||||||
user=self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.delete(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/?id={metadata.pk}",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
self.assertEqual(len(CustomMetadata.objects.all()), 0)
|
|
||||||
doc = Document.objects.get(pk=doc.pk)
|
|
||||||
# modified was updated to today
|
|
||||||
self.assertEqual(doc.modified.day, timezone.now().day)
|
|
||||||
|
|
||||||
def test_get_custom_metadata_no_doc(self):
|
|
||||||
"""
|
|
||||||
GIVEN:
|
|
||||||
- A request to get custom metadata from a non-existent document
|
|
||||||
WHEN:
|
|
||||||
- API request for document custom metadata is made
|
|
||||||
THEN:
|
|
||||||
- HTTP status.HTTP_404_NOT_FOUND is returned
|
|
||||||
"""
|
|
||||||
response = self.client.get(
|
|
||||||
"/api/documents/500/custom_metadata/",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
||||||
@mock.patch("documents.views.CustomMetadata.to_json")
|
|
||||||
def test_get_custom_metadata_failure(self, mocked_to_json: MagicMock):
|
|
||||||
mocked_to_json.side_effect = Exception("this failed somehow")
|
|
||||||
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom metadata on it! Neat",
|
|
||||||
)
|
|
||||||
|
|
||||||
_ = CustomMetadata.objects.create(
|
|
||||||
data_type=CustomMetadata.DataType.STRING,
|
|
||||||
name="Invoice Number",
|
|
||||||
data="#123456",
|
|
||||||
document=doc,
|
|
||||||
user=self.user,
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.get(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
format="json",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
|
|
||||||
@mock.patch("documents.views.CustomMetadata.from_json")
|
|
||||||
def test_add_custom_metadata_failure(self, mocked_from_json: MagicMock):
|
|
||||||
mocked_from_json.side_effect = Exception("this failed somehow else")
|
|
||||||
|
|
||||||
doc = Document.objects.create(
|
|
||||||
title="test",
|
|
||||||
mime_type="application/pdf",
|
|
||||||
content="this is a document which will have custom metadata on it! Neat",
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.client.post(
|
|
||||||
f"/api/documents/{doc.pk}/custom_metadata/",
|
|
||||||
data={"type": "string", "name": "Custom Field 1", "data": "Custom Data 1"},
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
@ -624,100 +624,6 @@ class DocumentViewSet(
|
|||||||
]
|
]
|
||||||
return Response(links)
|
return Response(links)
|
||||||
|
|
||||||
# @action(methods=["get", "post", "delete"], detail=True)
|
|
||||||
# def custom_metadata(self, request, pk=None) -> Response:
|
|
||||||
# def package_custom_metadata(doc: Document):
|
|
||||||
# return [
|
|
||||||
# c.to_json()
|
|
||||||
# for c in CustomMetadata.objects.filter(document=doc).order_by(
|
|
||||||
# "-created",
|
|
||||||
# )
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# request.user = request.user
|
|
||||||
# try:
|
|
||||||
# doc = Document.objects.get(pk=pk)
|
|
||||||
# if request.user is not None and not has_perms_owner_aware(
|
|
||||||
# request.user,
|
|
||||||
# "view_document",
|
|
||||||
# doc,
|
|
||||||
# ):
|
|
||||||
# return HttpResponseForbidden(
|
|
||||||
# "Insufficient permissions to view custom metadata",
|
|
||||||
# )
|
|
||||||
# except Document.DoesNotExist:
|
|
||||||
# raise Http404
|
|
||||||
|
|
||||||
# if request.method == "GET":
|
|
||||||
# try:
|
|
||||||
# return Response(package_custom_metadata(doc))
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.warning(f"An error occurred retrieving custom metadata: {e!s}")
|
|
||||||
# return HttpResponseServerError(
|
|
||||||
# {
|
|
||||||
# "error": (
|
|
||||||
# "Error retrieving custom metadata,"
|
|
||||||
# " check logs for more detail."
|
|
||||||
# ),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# elif request.method == "POST":
|
|
||||||
# try:
|
|
||||||
# if request.user is not None and not has_perms_owner_aware(
|
|
||||||
# request.user,
|
|
||||||
# "change_document",
|
|
||||||
# doc,
|
|
||||||
# ):
|
|
||||||
# return HttpResponseForbidden(
|
|
||||||
# "Insufficient permissions to create custom metadata",
|
|
||||||
# )
|
|
||||||
|
|
||||||
# CustomMetadata.from_json(doc, request.user, request.data)
|
|
||||||
|
|
||||||
# doc.modified = timezone.now()
|
|
||||||
# doc.save()
|
|
||||||
|
|
||||||
# from documents import index
|
|
||||||
|
|
||||||
# index.add_or_update_document(self.get_object())
|
|
||||||
|
|
||||||
# return Response(package_custom_metadata(doc))
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.warning(f"An error occurred saving custom metadata: {e!s}")
|
|
||||||
# return HttpResponseServerError(
|
|
||||||
# {
|
|
||||||
# "error": (
|
|
||||||
# "Error saving custom metadata, "
|
|
||||||
# "check logs for more detail."
|
|
||||||
# ),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# elif request.method == "DELETE":
|
|
||||||
# if request.user is not None and not has_perms_owner_aware(
|
|
||||||
# request.user,
|
|
||||||
# "change_document",
|
|
||||||
# doc,
|
|
||||||
# ):
|
|
||||||
# return HttpResponseForbidden(
|
|
||||||
# "Insufficient permissions to delete custom metadata",
|
|
||||||
# )
|
|
||||||
|
|
||||||
# metadata = CustomMetadata.objects.get(id=int(request.GET.get("id")))
|
|
||||||
# metadata.delete()
|
|
||||||
|
|
||||||
# doc.modified = timezone.now()
|
|
||||||
# doc.save()
|
|
||||||
|
|
||||||
# from documents import index
|
|
||||||
|
|
||||||
# index.add_or_update_document(self.get_object())
|
|
||||||
|
|
||||||
# return Response(package_custom_metadata(doc))
|
|
||||||
|
|
||||||
# return Response(
|
|
||||||
# {"error": "unreachable error was reached for custom metadata"},
|
|
||||||
# ) # pragma: no cover
|
|
||||||
|
|
||||||
|
|
||||||
class SearchResultSerializer(DocumentSerializer, PassUserMixin):
|
class SearchResultSerializer(DocumentSerializer, PassUserMixin):
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
@ -1441,7 +1347,7 @@ class ConsumptionTemplateViewSet(ModelViewSet):
|
|||||||
|
|
||||||
model = ConsumptionTemplate
|
model = ConsumptionTemplate
|
||||||
|
|
||||||
queryset = ConsumptionTemplate.objects.all().order_by("order")
|
queryset = ConsumptionTemplate.objects.all().order_by("name")
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldViewSet(ModelViewSet):
|
class CustomFieldViewSet(ModelViewSet):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user