Changeset View
Changeset View
Standalone View
Standalone View
swh/deposit/api/edit.py
# Copyright (C) 2017-2020 The Software Heritage developers | # Copyright (C) 2017-2020 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from typing import Any, Dict | from typing import Any, Dict | ||||
from rest_framework.request import Request | from rest_framework.request import Request | ||||
from swh.deposit.models import Deposit | from swh.deposit.models import Deposit | ||||
from swh.model.identifiers import parse_swhid | from swh.model.identifiers import parse_swhid | ||||
from ..config import DEPOSIT_STATUS_LOAD_SUCCESS | from ..config import DEPOSIT_STATUS_LOAD_SUCCESS | ||||
from ..errors import BAD_REQUEST, DepositError, ParserError, make_error_dict | from ..errors import BAD_REQUEST, DepositError, ParserError | ||||
from ..parsers import SWHAtomEntryParser, SWHMultiPartParser | from ..parsers import SWHAtomEntryParser, SWHMultiPartParser | ||||
from .common import APIDelete, APIPut, ParsedRequestHeaders | from .common import APIDelete, APIPut, ParsedRequestHeaders | ||||
class EditAPI(APIPut, APIDelete): | class EditAPI(APIPut, APIDelete): | ||||
"""Deposit request class defining api endpoints for sword deposit. | """Deposit request class defining api endpoints for sword deposit. | ||||
What's known as 'Edit-IRI' in the sword specification. | What's known as 'Edit-IRI' in the sword specification. | ||||
HTTP verbs supported: PUT, DELETE | HTTP verbs supported: PUT, DELETE | ||||
""" | """ | ||||
parser_classes = (SWHMultiPartParser, SWHAtomEntryParser) | parser_classes = (SWHMultiPartParser, SWHAtomEntryParser) | ||||
def restrict_access( | def restrict_access( | ||||
self, request: Request, headers: ParsedRequestHeaders, deposit: Deposit | self, request: Request, headers: ParsedRequestHeaders, deposit: Deposit | ||||
) -> Dict[str, Any]: | ) -> None: | ||||
"""Relax restriction access to allow metadata update on deposit with status "done" when | """Relax restriction access to allow metadata update on deposit with status "done" when | ||||
a swhid is provided. | a swhid is provided. | ||||
""" | """ | ||||
if ( | if ( | ||||
request.method == "PUT" | request.method == "PUT" | ||||
and headers.swhid is not None | and headers.swhid is not None | ||||
and deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS | and deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS | ||||
): | ): | ||||
# Allow metadata update on deposit with status "done" when swhid provided | # Allow metadata update on deposit with status "done" when swhid provided | ||||
return {} | return | ||||
# otherwise, let the standard access restriction check occur | # otherwise, let the standard access restriction check occur | ||||
return super().restrict_access(request, headers, deposit) | super().restrict_access(request, headers, deposit) | ||||
def process_put( | def process_put( | ||||
self, | self, | ||||
request, | request, | ||||
headers: ParsedRequestHeaders, | headers: ParsedRequestHeaders, | ||||
collection_name: str, | collection_name: str, | ||||
deposit_id: int, | deposit_id: int, | ||||
) -> Dict[str, Any]: | ) -> Dict[str, Any]: | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | ) -> Dict[str, Any]: | ||||
# Update metadata on a deposit already ingested | # Update metadata on a deposit already ingested | ||||
# Write to the metadata storage (and the deposit backend) | # Write to the metadata storage (and the deposit backend) | ||||
# no ingestion triggered | # no ingestion triggered | ||||
deposit = Deposit.objects.get(pk=deposit_id) | deposit = Deposit.objects.get(pk=deposit_id) | ||||
assert deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS | assert deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS | ||||
if swhid != deposit.swhid: | if swhid != deposit.swhid: | ||||
return make_error_dict( | raise DepositError( | ||||
BAD_REQUEST, | BAD_REQUEST, | ||||
f"Mismatched provided SWHID {swhid} with deposit's {deposit.swhid}.", | f"Mismatched provided SWHID {swhid} with deposit's {deposit.swhid}.", | ||||
"The provided SWHID does not match the deposit to update. " | "The provided SWHID does not match the deposit to update. " | ||||
"Please ensure you send the correct deposit SWHID.", | "Please ensure you send the correct deposit SWHID.", | ||||
) | ) | ||||
try: | try: | ||||
raw_metadata, metadata = self._read_metadata(request.data) | raw_metadata, metadata = self._read_metadata(request.data) | ||||
except ParserError: | except ParserError: | ||||
return make_error_dict( | raise DepositError( | ||||
BAD_REQUEST, | BAD_REQUEST, | ||||
"Malformed xml metadata", | "Malformed xml metadata", | ||||
"The xml received is malformed. " | "The xml received is malformed. " | ||||
"Please ensure your metadata file is correctly formatted.", | "Please ensure your metadata file is correctly formatted.", | ||||
) | ) | ||||
if not metadata: | if not metadata: | ||||
return make_error_dict( | raise DepositError( | ||||
BAD_REQUEST, | BAD_REQUEST, | ||||
"Empty body request is not supported", | "Empty body request is not supported", | ||||
"Atom entry deposit is supposed to send for metadata. " | "Atom entry deposit is supposed to send for metadata. " | ||||
"If the body is empty, there is no metadata.", | "If the body is empty, there is no metadata.", | ||||
) | ) | ||||
try: | |||||
_, _, deposit, deposit_request = self._store_metadata_deposit( | _, _, deposit, deposit_request = self._store_metadata_deposit( | ||||
deposit, parse_swhid(swhid), metadata, raw_metadata, deposit.origin_url, | deposit, parse_swhid(swhid), metadata, raw_metadata, deposit.origin_url, | ||||
) | ) | ||||
except DepositError as deposit_error: | |||||
return deposit_error.to_dict() | |||||
return { | return { | ||||
"deposit_id": deposit.id, | "deposit_id": deposit.id, | ||||
"deposit_date": deposit_request.date, | "deposit_date": deposit_request.date, | ||||
"status": deposit.status, | "status": deposit.status, | ||||
"archive": None, | "archive": None, | ||||
} | } | ||||
def process_delete(self, req, collection_name: str, deposit_id: int) -> Dict: | def process_delete(self, req, collection_name: str, deposit_id: int) -> Dict: | ||||
"""Delete the container (deposit). | """Delete the container (deposit). | ||||
source: http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_deleteconteiner # noqa | source: http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_deleteconteiner # noqa | ||||
""" | """ | ||||
return self._delete_deposit(collection_name, deposit_id) | return self._delete_deposit(collection_name, deposit_id) |