diff --git a/swh/deposit/api/private/deposit_list.py b/swh/deposit/api/private/deposit_list.py --- a/swh/deposit/api/private/deposit_list.py +++ b/swh/deposit/api/private/deposit_list.py @@ -23,20 +23,35 @@ pagination_class = DefaultPagination def get_queryset(self): + """Retrieve iterable of deposits (with some optional filtering).""" params = self.request.query_params exclude_like = params.get("exclude") username = params.get("username") if username: - deposits = Deposit.objects.select_related("client").filter( + deposits_qs = Deposit.objects.select_related("client").filter( client__username=username ) else: - deposits = Deposit.objects.all() + deposits_qs = Deposit.objects.all() if exclude_like: # sql injection: A priori, nothing to worry about, django does it for # queryset # https://docs.djangoproject.com/en/3.0/topics/security/#sql-injection-protection # noqa - deposits = deposits.exclude(external_id__startswith=exclude_like) - return deposits.order_by("id") + deposits_qs = deposits_qs.exclude(external_id__startswith=exclude_like) + + deposits = [] + for deposit in deposits_qs.order_by("id"): + deposit_requests = deposit.depositrequest_set.filter( + type="metadata" + ).order_by("-id") + # enrich deposit with raw metadata when we have some + if deposit_requests and len(deposit_requests) > 0: + raw_meta = deposit_requests[0].raw_metadata + if raw_meta: + deposit.set_raw_metadata(raw_meta) + + deposits.append(deposit) + + return deposits diff --git a/swh/deposit/api/utils.py b/swh/deposit/api/utils.py --- a/swh/deposit/api/utils.py +++ b/swh/deposit/api/utils.py @@ -29,6 +29,7 @@ class DepositSerializer(serializers.ModelSerializer): status_detail = StatusDetailField() + raw_metadata = _UnvalidatedField() class Meta: model = Deposit diff --git a/swh/deposit/models.py b/swh/deposit/models.py --- a/swh/deposit/models.py +++ b/swh/deposit/models.py @@ -147,6 +147,7 @@ load_task_id = models.TextField( blank=True, null=True, verbose_name="Scheduler's associated loading task id" ) + raw_metadata: Optional[str] = None class Meta: db_table = "deposit" @@ -167,6 +168,13 @@ d["status_detail"] = self.status_detail return str(d) + def set_raw_metadata(self, raw_metadata: str) -> None: + """Set the metadata raw out of a 'metadata' typed deposit request. This is + specifically used during listing. + + """ + self.raw_metadata = raw_metadata + def client_directory_path(instance: "DepositRequest", filename: str) -> str: """Callable to determine the upload archive path. This defaults to diff --git a/swh/deposit/tests/api/test_deposit_private_list.py b/swh/deposit/tests/api/test_deposit_private_list.py --- a/swh/deposit/tests/api/test_deposit_private_list.py +++ b/swh/deposit/tests/api/test_deposit_private_list.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2021 The Software Heritage developers +# Copyright (C) 2017-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -8,7 +8,6 @@ from swh.deposit.api.converters import convert_status_detail from swh.deposit.config import ( - DEPOSIT_STATUS_DEPOSITED, DEPOSIT_STATUS_LOAD_SUCCESS, DEPOSIT_STATUS_PARTIAL, PRIVATE_LIST_DEPOSITS, @@ -29,15 +28,17 @@ } -def test_deposit_list(partial_deposit, deposited_deposit, authenticated_client): +def test_deposit_list( + partial_deposit_with_metadata, partial_deposit_only_metadata, authenticated_client +): """Deposit list api should return all deposits in a paginated way """ - partial_deposit.status_detail = STATUS_DETAIL - partial_deposit.save() + partial_deposit_with_metadata.status_detail = STATUS_DETAIL + partial_deposit_with_metadata.save() - deposit_id = partial_deposit.id - deposit_id2 = deposited_deposit.id + deposit_id = partial_deposit_with_metadata.id + deposit_id2 = partial_deposit_only_metadata.id main_url = reverse(PRIVATE_LIST_DEPOSITS) url = "%s?page_size=1" % main_url @@ -55,6 +56,7 @@ assert deposit["status"] == DEPOSIT_STATUS_PARTIAL expected_status_detail = convert_status_detail(STATUS_DETAIL) assert deposit["status_detail"] == expected_status_detail + assert deposit["raw_metadata"] is not None # then 2nd page response2 = authenticated_client.get(expected_next) @@ -71,22 +73,25 @@ deposit2 = data2["results"][0] assert deposit2["id"] == deposit_id2 - assert deposit2["status"] == DEPOSIT_STATUS_DEPOSITED + assert deposit2["status"] == DEPOSIT_STATUS_PARTIAL + assert deposit2["raw_metadata"] is not None -def test_deposit_list_exclude(partial_deposit, deposited_deposit, authenticated_client): +def test_deposit_list_exclude( + partial_deposit_with_metadata, partial_deposit_only_metadata, authenticated_client +): """Exclusion pattern on external_id should be respected """ - partial_deposit.status_detail = STATUS_DETAIL - partial_deposit.save() + partial_deposit_with_metadata.status_detail = STATUS_DETAIL + partial_deposit_with_metadata.save() main_url = reverse(PRIVATE_LIST_DEPOSITS) # Testing exclusion pattern exclude_pattern = "external-id" - assert partial_deposit.external_id.startswith(exclude_pattern) - assert deposited_deposit.external_id.startswith(exclude_pattern) + assert partial_deposit_with_metadata.external_id.startswith(exclude_pattern) + assert partial_deposit_only_metadata.external_id.startswith(exclude_pattern) url = f"{main_url}?page_size=1&exclude=external-id" response = authenticated_client.get(url) assert response.status_code == status.HTTP_200_OK