mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
936 lines
30 KiB
Python
936 lines
30 KiB
Python
import json
|
|
from datetime import date
|
|
|
|
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 CustomFieldInstance
|
|
from documents.models import Document
|
|
from documents.tests.utils import DirectoriesMixin
|
|
|
|
|
|
class TestCustomFieldsAPI(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 #"),
|
|
("boolean", "Is Active"),
|
|
("float", "Average Value"),
|
|
("monetary", "Total Paid"),
|
|
("documentlink", "Related Documents"),
|
|
]:
|
|
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(data["name"], name)
|
|
self.assertEqual(data["data_type"], field_type)
|
|
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "select",
|
|
"name": "Select Field",
|
|
"extra_data": {
|
|
"select_options": ["Option 1", "Option 2"],
|
|
},
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
|
|
|
data = resp.json()
|
|
|
|
self.assertCountEqual(
|
|
data["extra_data"]["select_options"],
|
|
["Option 1", "Option 2"],
|
|
)
|
|
|
|
def test_create_custom_field_nonunique_name(self):
|
|
"""
|
|
GIVEN:
|
|
- Custom field exists
|
|
WHEN:
|
|
- API request to create custom field with the same name
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
"""
|
|
CustomField.objects.create(
|
|
name="Test Custom Field",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
data={
|
|
"data_type": "string",
|
|
"name": "Test Custom Field",
|
|
},
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
def test_create_custom_field_select_invalid_options(self):
|
|
"""
|
|
GIVEN:
|
|
- Custom field does not exist
|
|
WHEN:
|
|
- API request to create custom field with invalid select options
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
"""
|
|
|
|
# Not a list
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "select",
|
|
"name": "Select Field",
|
|
"extra_data": {
|
|
"select_options": "not a list",
|
|
},
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
# No options
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "select",
|
|
"name": "Select Field",
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
def test_create_custom_field_monetary_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Custom field does not exist
|
|
WHEN:
|
|
- API request to create custom field with invalid default currency option
|
|
- API request to create custom field with valid default currency option
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- HTTP 201 is returned
|
|
"""
|
|
|
|
# not a string
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "monetary",
|
|
"name": "Monetary Field",
|
|
"extra_data": {
|
|
"default_currency": 123,
|
|
},
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
# not a 3-letter currency code
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "monetary",
|
|
"name": "Monetary Field",
|
|
"extra_data": {
|
|
"default_currency": "EU",
|
|
},
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
# valid currency code
|
|
resp = self.client.post(
|
|
self.ENDPOINT,
|
|
json.dumps(
|
|
{
|
|
"data_type": "monetary",
|
|
"name": "Monetary Field",
|
|
"extra_data": {
|
|
"default_currency": "EUR",
|
|
},
|
|
},
|
|
),
|
|
content_type="application/json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
|
|
|
def test_create_custom_field_instance(self):
|
|
"""
|
|
GIVEN:
|
|
- Field of each data type is created
|
|
WHEN:
|
|
- API request to create custom metadata instance with each data type
|
|
THEN:
|
|
- the field instance is created
|
|
- the field returns the correct fields and values
|
|
- the field is attached to the given document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
doc2 = Document.objects.create(
|
|
title="WOW2",
|
|
content="the content2",
|
|
checksum="1234",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field String",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
custom_field_date = CustomField.objects.create(
|
|
name="Test Custom Field Date",
|
|
data_type=CustomField.FieldDataType.DATE,
|
|
)
|
|
custom_field_int = CustomField.objects.create(
|
|
name="Test Custom Field Int",
|
|
data_type=CustomField.FieldDataType.INT,
|
|
)
|
|
custom_field_boolean = CustomField.objects.create(
|
|
name="Test Custom Field Boolean",
|
|
data_type=CustomField.FieldDataType.BOOL,
|
|
)
|
|
custom_field_url = CustomField.objects.create(
|
|
name="Test Custom Field Url",
|
|
data_type=CustomField.FieldDataType.URL,
|
|
)
|
|
custom_field_float = CustomField.objects.create(
|
|
name="Test Custom Field Float",
|
|
data_type=CustomField.FieldDataType.FLOAT,
|
|
)
|
|
custom_field_monetary = CustomField.objects.create(
|
|
name="Test Custom Field Monetary",
|
|
data_type=CustomField.FieldDataType.MONETARY,
|
|
)
|
|
custom_field_monetary2 = CustomField.objects.create(
|
|
name="Test Custom Field Monetary 2",
|
|
data_type=CustomField.FieldDataType.MONETARY,
|
|
)
|
|
custom_field_documentlink = CustomField.objects.create(
|
|
name="Test Custom Field Doc Link",
|
|
data_type=CustomField.FieldDataType.DOCUMENTLINK,
|
|
)
|
|
custom_field_select = CustomField.objects.create(
|
|
name="Test Custom Field Select",
|
|
data_type=CustomField.FieldDataType.SELECT,
|
|
extra_data={
|
|
"select_options": ["Option 1", "Option 2"],
|
|
},
|
|
)
|
|
|
|
date_value = date.today()
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_string.id,
|
|
"value": "test value",
|
|
},
|
|
{
|
|
"field": custom_field_date.id,
|
|
"value": date_value.isoformat(),
|
|
},
|
|
{
|
|
"field": custom_field_int.id,
|
|
"value": 3,
|
|
},
|
|
{
|
|
"field": custom_field_boolean.id,
|
|
"value": True,
|
|
},
|
|
{
|
|
"field": custom_field_url.id,
|
|
"value": "https://example.com",
|
|
},
|
|
{
|
|
"field": custom_field_float.id,
|
|
"value": 12.3456,
|
|
},
|
|
{
|
|
"field": custom_field_monetary.id,
|
|
"value": "EUR11.10",
|
|
},
|
|
{
|
|
"field": custom_field_monetary2.id,
|
|
"value": 11.10, # Legacy format
|
|
},
|
|
{
|
|
"field": custom_field_documentlink.id,
|
|
"value": [doc2.id],
|
|
},
|
|
{
|
|
"field": custom_field_select.id,
|
|
"value": 0,
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
|
|
resp_data = resp.json()["custom_fields"]
|
|
|
|
self.assertCountEqual(
|
|
resp_data,
|
|
[
|
|
{"field": custom_field_string.id, "value": "test value"},
|
|
{"field": custom_field_date.id, "value": date_value.isoformat()},
|
|
{"field": custom_field_int.id, "value": 3},
|
|
{"field": custom_field_boolean.id, "value": True},
|
|
{"field": custom_field_url.id, "value": "https://example.com"},
|
|
{"field": custom_field_float.id, "value": 12.3456},
|
|
{"field": custom_field_monetary.id, "value": "EUR11.10"},
|
|
{"field": custom_field_monetary2.id, "value": "11.1"},
|
|
{"field": custom_field_documentlink.id, "value": [doc2.id]},
|
|
{"field": custom_field_select.id, "value": 0},
|
|
],
|
|
)
|
|
|
|
doc.refresh_from_db()
|
|
self.assertEqual(len(doc.custom_fields.all()), 10)
|
|
|
|
def test_change_custom_field_instance_value(self):
|
|
"""
|
|
GIVEN:
|
|
- Custom field instance is created and attached to document
|
|
WHEN:
|
|
- API request to create change the value of the custom field
|
|
THEN:
|
|
- the field instance is updated
|
|
- the field returns the correct fields and values
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field String",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
|
|
# Create
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_string.id,
|
|
"value": "test value",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 1)
|
|
self.assertEqual(doc.custom_fields.first().value, "test value")
|
|
|
|
# Update
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_string.id,
|
|
"value": "a new test value",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 1)
|
|
self.assertEqual(doc.custom_fields.first().value, "a new test value")
|
|
|
|
def test_delete_custom_field_instance(self):
|
|
"""
|
|
GIVEN:
|
|
- Multiple custom field instances are created and attached to document
|
|
WHEN:
|
|
- API request to remove a field
|
|
THEN:
|
|
- the field instance is removed
|
|
- the other field remains unchanged
|
|
- the field returns the correct fields and values
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field String",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
custom_field_date = CustomField.objects.create(
|
|
name="Test Custom Field Date",
|
|
data_type=CustomField.FieldDataType.DATE,
|
|
)
|
|
|
|
date_value = date.today()
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_string.id,
|
|
"value": "a new test value",
|
|
},
|
|
{
|
|
"field": custom_field_date.id,
|
|
"value": date_value.isoformat(),
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 2)
|
|
self.assertEqual(len(doc.custom_fields.all()), 2)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_date.id,
|
|
"value": date_value.isoformat(),
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 1)
|
|
self.assertEqual(Document.objects.count(), 1)
|
|
self.assertEqual(len(doc.custom_fields.all()), 1)
|
|
self.assertEqual(doc.custom_fields.first().value, date_value)
|
|
|
|
def test_custom_field_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document exists with no fields
|
|
WHEN:
|
|
- API request to remove a field
|
|
- API request is not valid
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field created
|
|
- No field attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field String",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_string.id,
|
|
# Whoops, spelling
|
|
"valeu": "a new test value",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
|
|
def test_custom_field_value_url_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document & custom field exist
|
|
WHEN:
|
|
- API request to set a field value to something which is or is not a link
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field instance is created or attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_url = CustomField.objects.create(
|
|
name="Test Custom Field URL",
|
|
data_type=CustomField.FieldDataType.URL,
|
|
)
|
|
|
|
for value in ["not a url", "file:"]:
|
|
with self.subTest(f"Test value {value}"):
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_url.id,
|
|
"value": value,
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_url.id,
|
|
"value": "tel:+1-816-555-1212",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
|
|
def test_custom_field_value_integer_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document & custom field exist
|
|
WHEN:
|
|
- API request to set a field value to something not an integer
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field instance is created or attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_int = CustomField.objects.create(
|
|
name="Test Custom Field INT",
|
|
data_type=CustomField.FieldDataType.INT,
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_int.id,
|
|
"value": "not an int",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
|
|
def test_custom_field_value_monetary_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document & custom field exist
|
|
WHEN:
|
|
- API request to set a field value to something not a valid monetary decimal (legacy) or not a new monetary format e.g. USD12.34
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field instance is created or attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_money = CustomField.objects.create(
|
|
name="Test Custom Field MONETARY",
|
|
data_type=CustomField.FieldDataType.MONETARY,
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_money.id,
|
|
# Too many places past decimal
|
|
"value": 12.123,
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_money.id,
|
|
# Too many places past decimal
|
|
"value": "GBP12.123",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_money.id,
|
|
# Not a 3-letter currency code
|
|
"value": "G12.12",
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
|
|
def test_custom_field_value_short_text_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document & custom field exist
|
|
WHEN:
|
|
- API request to set a field value to a too long string
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field instance is created or attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field STRING",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{"field": custom_field_string.id, "value": "a" * 129},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
|
|
def test_custom_field_value_select_validation(self):
|
|
"""
|
|
GIVEN:
|
|
- Document & custom field exist
|
|
WHEN:
|
|
- API request to set a field value to something not in the select options
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
- No field instance is created or attached to the document
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_select = CustomField.objects.create(
|
|
name="Test Custom Field SELECT",
|
|
data_type=CustomField.FieldDataType.SELECT,
|
|
extra_data={
|
|
"select_options": ["Option 1", "Option 2"],
|
|
},
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{"field": custom_field_select.id, "value": 3},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 0)
|
|
self.assertEqual(len(doc.custom_fields.all()), 0)
|
|
|
|
def test_custom_field_not_null(self):
|
|
"""
|
|
GIVEN:
|
|
- Existing document
|
|
WHEN:
|
|
- API request with custom_fields set to null
|
|
THEN:
|
|
- HTTP 400 is returned
|
|
"""
|
|
doc = Document.objects.create(
|
|
title="WOW",
|
|
content="the content",
|
|
checksum="123",
|
|
mime_type="application/pdf",
|
|
)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc.id}/",
|
|
data={
|
|
"custom_fields": None,
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
|
|
|
def test_symmetric_doclink_fields(self):
|
|
"""
|
|
GIVEN:
|
|
- Existing document
|
|
WHEN:
|
|
- Doc links are added or removed
|
|
THEN:
|
|
- Symmetrical link is created or removed as expected
|
|
"""
|
|
doc1 = Document.objects.create(
|
|
title="WOW1",
|
|
content="1",
|
|
checksum="1",
|
|
mime_type="application/pdf",
|
|
)
|
|
doc2 = Document.objects.create(
|
|
title="WOW2",
|
|
content="the content2",
|
|
checksum="2",
|
|
mime_type="application/pdf",
|
|
)
|
|
doc3 = Document.objects.create(
|
|
title="WOW3",
|
|
content="the content3",
|
|
checksum="3",
|
|
mime_type="application/pdf",
|
|
)
|
|
doc4 = Document.objects.create(
|
|
title="WOW4",
|
|
content="the content4",
|
|
checksum="4",
|
|
mime_type="application/pdf",
|
|
)
|
|
custom_field_doclink = CustomField.objects.create(
|
|
name="Test Custom Field Doc Link",
|
|
data_type=CustomField.FieldDataType.DOCUMENTLINK,
|
|
)
|
|
|
|
# Add links, creates bi-directional
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc1.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_doclink.id,
|
|
"value": [2, 3, 4],
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(CustomFieldInstance.objects.count(), 4)
|
|
self.assertEqual(doc2.custom_fields.first().value, [1])
|
|
self.assertEqual(doc3.custom_fields.first().value, [1])
|
|
self.assertEqual(doc4.custom_fields.first().value, [1])
|
|
|
|
# Add links appends if necessary
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc3.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_doclink.id,
|
|
"value": [1, 4],
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(doc4.custom_fields.first().value, [1, 3])
|
|
|
|
# Remove one of the links, removed on other doc
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc1.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_doclink.id,
|
|
"value": [2, 3],
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(doc2.custom_fields.first().value, [1])
|
|
self.assertEqual(doc3.custom_fields.first().value, [1, 4])
|
|
self.assertEqual(doc4.custom_fields.first().value, [3])
|
|
|
|
# Removes the field entirely
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc1.id}/",
|
|
data={
|
|
"custom_fields": [],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(doc2.custom_fields.first().value, [])
|
|
self.assertEqual(doc3.custom_fields.first().value, [4])
|
|
self.assertEqual(doc4.custom_fields.first().value, [3])
|
|
|
|
# If field exists on target doc but value is None
|
|
doc5 = Document.objects.create(
|
|
title="WOW5",
|
|
content="the content4",
|
|
checksum="5",
|
|
mime_type="application/pdf",
|
|
)
|
|
CustomFieldInstance.objects.create(document=doc5, field=custom_field_doclink)
|
|
|
|
resp = self.client.patch(
|
|
f"/api/documents/{doc1.id}/",
|
|
data={
|
|
"custom_fields": [
|
|
{
|
|
"field": custom_field_doclink.id,
|
|
"value": [doc5.id],
|
|
},
|
|
],
|
|
},
|
|
format="json",
|
|
)
|
|
|
|
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
|
self.assertEqual(doc5.custom_fields.first().value, [1])
|
|
|
|
def test_custom_field_filters(self):
|
|
custom_field_string = CustomField.objects.create(
|
|
name="Test Custom Field String",
|
|
data_type=CustomField.FieldDataType.STRING,
|
|
)
|
|
custom_field_date = CustomField.objects.create(
|
|
name="Test Custom Field Date",
|
|
data_type=CustomField.FieldDataType.DATE,
|
|
)
|
|
custom_field_int = CustomField.objects.create(
|
|
name="Test Custom Field Int",
|
|
data_type=CustomField.FieldDataType.INT,
|
|
)
|
|
|
|
response = self.client.get(
|
|
f"{self.ENDPOINT}?id={custom_field_string.id}",
|
|
)
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
results = response.data["results"]
|
|
self.assertEqual(len(results), 1)
|
|
|
|
response = self.client.get(
|
|
f"{self.ENDPOINT}?id__in={custom_field_string.id},{custom_field_date.id}",
|
|
)
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
results = response.data["results"]
|
|
self.assertEqual(len(results), 2)
|
|
|
|
response = self.client.get(
|
|
f"{self.ENDPOINT}?name__icontains=Int",
|
|
)
|
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
results = response.data["results"]
|
|
self.assertEqual(len(results), 1)
|
|
self.assertEqual(results[0]["name"], custom_field_int.name)
|