Repository: paperless-ngx/paperless-ngx

Issue:
Configuration: User-Arguments are mandatory
### Description

See the following Screenshot. 

![image](https://github.com/paperless-ngx/paperless-ngx/assets/88422038/b2bc5f45-b45d-43c5-99f7-076ae4c6764d)

I don't think, user args should be mandatory, since the documentation says "additionally specify arguments".

### Steps to reproduce

1. Click on "Configuration"
2. Fill in some Values
3. Click "Save"
4. User-Args are mandatory

In order to save a Configuration, the user now has to enter an empty json which is not very user-friendly.

### Webserver logs

```bash
not applicable
```


### Browser logs

_No response_

### Paperless-ngx version

2.3.2

### Host OS

Synology DSM 6.2.X

### Installation method

Docker - official image

### Browser

Chrome

### Configuration changes

none of interest

### Other

_No response_

### Please confirm the following

- [X] I believe this issue is a bug that affects all users of Paperless-ngx, not something specific to my installation.
- [X] I have already searched for relevant existing issues and discussions before opening this report.
- [X] I have updated the title field above with a concise description.


Discussion:
Looks like we'll need the `null=True`, since that isn't being picked up from the model.  @shamoon looks like you're getting this?
Actually please feel free stumpy my virtualenv exploded last night 😥

Resolving patch:
diff --git a/src/paperless/serialisers.py b/src/paperless/serialisers.py
--- a/src/paperless/serialisers.py
+++ b/src/paperless/serialisers.py
@@ -122,7 +122,12 @@ class Meta:
 
 
 class ApplicationConfigurationSerializer(serializers.ModelSerializer):
-    user_args = serializers.JSONField(binary=True)
+    user_args = serializers.JSONField(binary=True, allow_null=True)
+
+    def run_validation(self, data):
+        if "user_args" in data and data["user_args"] == "":
+            data["user_args"] = None
+        return super().run_validation(data)
 
     class Meta:
         model = ApplicationConfiguration


Test patch:
diff --git a/src/documents/tests/test_api_app_config.py b/src/documents/tests/test_api_app_config.py
new file mode 100644
--- /dev/null
+++ b/src/documents/tests/test_api_app_config.py
@@ -0,0 +1,100 @@
+import json
+
+from django.contrib.auth.models import User
+from rest_framework import status
+from rest_framework.test import APITestCase
+
+from documents.tests.utils import DirectoriesMixin
+from paperless.models import ApplicationConfiguration
+from paperless.models import ColorConvertChoices
+
+
+class TestApiAppConfig(DirectoriesMixin, APITestCase):
+    ENDPOINT = "/api/config/"
+
+    def setUp(self) -> None:
+        super().setUp()
+
+        user = User.objects.create_superuser(username="temp_admin")
+        self.client.force_authenticate(user=user)
+
+    def test_api_get_config(self):
+        """
+        GIVEN:
+            - API request to get app config
+        WHEN:
+            - API is called
+        THEN:
+            - Existing config
+        """
+        response = self.client.get(self.ENDPOINT, format="json")
+
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        self.assertEqual(
+            json.dumps(response.data[0]),
+            json.dumps(
+                {
+                    "id": 1,
+                    "user_args": None,
+                    "output_type": None,
+                    "pages": None,
+                    "language": None,
+                    "mode": None,
+                    "skip_archive_file": None,
+                    "image_dpi": None,
+                    "unpaper_clean": None,
+                    "deskew": None,
+                    "rotate_pages": None,
+                    "rotate_pages_threshold": None,
+                    "max_image_pixels": None,
+                    "color_conversion_strategy": None,
+                },
+            ),
+        )
+
+    def test_api_update_config(self):
+        """
+        GIVEN:
+            - API request to update app config
+        WHEN:
+            - API is called
+        THEN:
+            - Correct HTTP response
+            - Config is updated
+        """
+        response = self.client.patch(
+            f"{self.ENDPOINT}1/",
+            json.dumps(
+                {
+                    "color_conversion_strategy": ColorConvertChoices.RGB,
+                },
+            ),
+            content_type="application/json",
+        )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        config = ApplicationConfiguration.objects.first()
+        self.assertEqual(config.color_conversion_strategy, ColorConvertChoices.RGB)
+
+    def test_api_update_config_empty_json_field(self):
+        """
+        GIVEN:
+            - API request to update app config with empty string for user_args JSONField
+        WHEN:
+            - API is called
+        THEN:
+            - Correct HTTP response
+            - user_args is set to None
+        """
+        response = self.client.patch(
+            f"{self.ENDPOINT}1/",
+            json.dumps(
+                {
+                    "user_args": "",
+                },
+            ),
+            content_type="application/json",
+        )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        config = ApplicationConfiguration.objects.first()
+        self.assertEqual(config.user_args, None)