Fix: handle versioned PaperlessTasks response

This commit is contained in:
shamoon 2025-03-08 16:38:12 -08:00
parent b746b6f2d6
commit 337092f345
7 changed files with 86 additions and 15 deletions

View File

@ -413,3 +413,11 @@ Initial API version.
list of strings. When creating or updating a custom field value of a
document for a select type custom field, the value should be the `id` of
the option whereas previously was the index of the option.
#### Version 8
- PaperlessTask objects now have a `task_name` field which replaces the old
`type` field. The `type` field is now used to represent the way the task
was created. Additionally, the tasks endpoint now returns different types
of tasks other than simply 'file' tasks. See the API schema for more
information.

View File

@ -3,7 +3,7 @@ const base_url = new URL(document.baseURI)
export const environment = {
production: true,
apiBaseUrl: document.baseURI + 'api/',
apiVersion: '7',
apiVersion: '8',
appTitle: 'Paperless-ngx',
version: '2.14.7',
webSocketHost: window.location.host,

View File

@ -5,7 +5,7 @@
export const environment = {
production: false,
apiBaseUrl: 'http://localhost:8000/api/',
apiVersion: '7',
apiVersion: '8',
appTitle: 'Paperless-ngx',
version: 'DEVELOPMENT',
webSocketHost: 'localhost:8000',

View File

@ -421,6 +421,15 @@ class OwnedObjectListSerializer(serializers.ListSerializer):
return super().to_representation(documents)
class GetAPIVersionMixin:
def get_api_version(self):
return int(
self.context.get("request").version
if self.context.get("request")
else settings.REST_FRAMEWORK["DEFAULT_VERSION"],
)
class CorrespondentSerializer(MatchingModelSerializer, OwnedObjectSerializer):
last_correspondence = serializers.DateTimeField(read_only=True, required=False)
@ -717,7 +726,7 @@ class ReadWriteSerializerMethodField(serializers.SerializerMethodField):
return {self.field_name: data}
class CustomFieldInstanceSerializer(serializers.ModelSerializer):
class CustomFieldInstanceSerializer(serializers.ModelSerializer, GetAPIVersionMixin):
field = serializers.PrimaryKeyRelatedField(queryset=CustomField.objects.all())
value = ReadWriteSerializerMethodField(allow_null=True)
@ -809,13 +818,6 @@ class CustomFieldInstanceSerializer(serializers.ModelSerializer):
return data
def get_api_version(self):
return int(
self.context.get("request").version
if self.context.get("request")
else settings.REST_FRAMEWORK["DEFAULT_VERSION"],
)
def to_internal_value(self, data):
ret = super().to_internal_value(data)
@ -1709,7 +1711,7 @@ class UiSettingsViewSerializer(serializers.ModelSerializer):
return ui_settings
class TasksViewSerializer(OwnedObjectSerializer):
class TasksViewSerializer(OwnedObjectSerializer, GetAPIVersionMixin):
class Meta:
model = PaperlessTask
fields = (
@ -1752,6 +1754,13 @@ class TasksViewSerializer(OwnedObjectSerializer):
return result
def to_representation(self, instance: PaperlessTask):
result = super().to_representation(instance)
if self.get_api_version() < 8:
# Older versions only returned file tasks (filtering handled in view) and had different naming scheme
result["type"] = "file"
return result
class RunTaskViewSerializer(serializers.Serializer):
task_name = serializers.ChoiceField(

View File

@ -370,3 +370,45 @@ class TestTasks(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
mock_check_sanity.assert_not_called()
def test_handle_older_api_version(self):
"""
GIVEN:
- A request from the API with version < 8
WHEN:
- Tasks are requested
THEN:
- Only consume file tasks are returned and the type is 'file'
"""
task1 = PaperlessTask.objects.create(
task_id=str(uuid.uuid4()),
task_file_name="task_one.pdf",
task_name=PaperlessTask.TaskName.CONSUME_FILE,
)
task2 = PaperlessTask.objects.create(
task_id=str(uuid.uuid4()),
task_name=PaperlessTask.TaskName.CHECK_SANITY,
type=PaperlessTask.TaskType.AUTO,
)
response = self.client.get(
self.ENDPOINT,
headers={"Accept": "application/json; version=7"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
self.assertEqual(response.data[0]["task_id"], task1.task_id)
self.assertEqual(response.data[0]["type"], "file")
response = self.client.get(
self.ENDPOINT,
headers={"Accept": "application/json; version=8"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2)
self.assertEqual(response.data[0]["task_id"], task2.task_id)
self.assertEqual(response.data[0]["type"], PaperlessTask.TaskType.AUTO)

View File

@ -2287,6 +2287,7 @@ class TasksViewSet(ReadOnlyModelViewSet):
ObjectOwnedOrGrantedPermissionsFilter,
)
filterset_class = PaperlessTaskFilterSet
queryset = PaperlessTask.objects.all().order_by("-date_created")
TASK_AND_ARGS_BY_NAME = {
PaperlessTask.TaskName.INDEX_OPTIMIZE: (index_optimize, {}),
@ -2301,11 +2302,22 @@ class TasksViewSet(ReadOnlyModelViewSet):
}
def get_queryset(self):
queryset = PaperlessTask.objects.all().order_by("-date_created")
task_id = self.request.query_params.get("task_id")
if task_id is not None:
queryset = PaperlessTask.objects.filter(task_id=task_id)
return queryset
return PaperlessTask.objects.filter(task_id=task_id)
return super().get_queryset()
def list(self, request, *args, **kwargs):
version = int(
request.version if request else settings.REST_FRAMEWORK["DEFAULT_VERSION"],
)
if version < 8:
# Previous API versions only had file tasks, the format is also different (handled in serializer)
self.queryset = PaperlessTask.objects.filter(
task_name=PaperlessTask.TaskName.CONSUME_FILE,
).order_by("-date_created")
return super().list(request, *args, **kwargs)
@action(methods=["post"], detail=False)
def acknowledge(self, request):

View File

@ -345,7 +345,7 @@ REST_FRAMEWORK = {
"DEFAULT_VERSION": "7",
# Make sure these are ordered and that the most recent version appears
# last. See api.md#api-versioning when adding new versions.
"ALLOWED_VERSIONS": ["1", "2", "3", "4", "5", "6", "7"],
"ALLOWED_VERSIONS": ["1", "2", "3", "4", "5", "6", "7", "8"],
# DRF Spectacular default schema
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
}