# Copyright (C) 2017-2020 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
from rest_framework.request import Request
from swh.deposit.api.common import APIDelete, APIPut, ParsedRequestHeaders
from swh.deposit.config import DEPOSIT_STATUS_LOAD_SUCCESS
from swh.deposit.errors import BAD_REQUEST, DepositError, ParserError
from swh.deposit.models import Deposit
from swh.deposit.parsers import SWHAtomEntryParser, SWHMultiPartParser
from swh.model.swhids import QualifiedSWHID
[docs]
class EditAPI(APIPut, APIDelete):
"""Deposit request class defining api endpoints for sword deposit.
What's known as 'Edit-IRI' in the sword specification.
HTTP verbs supported: PUT, DELETE
"""
parser_classes = (SWHMultiPartParser, SWHAtomEntryParser)
[docs]
def restrict_access(
self, request: Request, headers: ParsedRequestHeaders, deposit: Deposit
) -> None:
"""Relax restriction access to allow metadata update on deposit with status "done" when
a swhid is provided.
"""
if (
request.method == "PUT"
and headers.swhid is not None
and deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS
):
# Allow metadata update on deposit with status "done" when swhid provided
return
# otherwise, let the standard access restriction check occur
super().restrict_access(request, headers, deposit)
[docs]
def process_put(
self,
request,
headers: ParsedRequestHeaders,
collection_name: str,
deposit: Deposit,
) -> None:
"""This allows the following scenarios:
- multipart: replace all the deposit (status partial) metadata and archive
with the provided ones.
- atom: replace all the deposit (status partial) metadata with the
provided ones.
- with swhid, atom: Add new metadata to deposit (status done) with provided ones
and push such metadata to the metadata storage directly.
source:
- http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_editingcontent_metadata
- http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_editingcontent_multipart
Raises:
400 if any of the following occur:
- the swhid provided and the deposit swhid do not match
- the provided metadata xml file is malformed
- the provided xml atom entry is empty
- the provided swhid does not exist in the archive
""" # noqa
swhid = headers.swhid
if swhid is None:
if request.content_type.startswith("multipart/"):
self._multipart_upload(
request,
headers,
collection_name,
deposit=deposit,
replace_archives=True,
replace_metadata=True,
)
else:
# standard metadata update (replace all metadata already provided to the
# deposit by the new ones)
self._atom_entry(
request,
headers,
collection_name,
deposit=deposit,
replace_metadata=True,
)
return
# Update metadata on a deposit already ingested
# Write to the metadata storage (and the deposit backend)
# no ingestion triggered
assert deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS
if swhid != deposit.swhid:
raise DepositError(
BAD_REQUEST,
f"Mismatched provided SWHID {swhid} with deposit's {deposit.swhid}.",
"The provided SWHID does not match the deposit to update. "
"Please ensure you send the correct deposit SWHID.",
)
try:
raw_metadata, metadata_tree = self._read_metadata(request.data)
except ParserError:
raise DepositError(
BAD_REQUEST,
"Malformed xml metadata",
"The xml received is malformed. "
"Please ensure your metadata file is correctly formatted.",
)
if len(metadata_tree) == 0:
raise DepositError(
BAD_REQUEST,
"Empty body request is not supported",
"Atom entry deposit is supposed to send for metadata. "
"If the body is empty, there is no metadata.",
)
_, deposit, deposit_request = self._store_metadata_deposit(
deposit,
QualifiedSWHID.from_string(swhid),
metadata_tree,
raw_metadata,
deposit.origin_url,
)
[docs]
def process_delete(self, req, collection_name: str, deposit: Deposit) -> None:
"""Delete the container (deposit).
source: http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_deleteconteiner # noqa
"""
self._delete_deposit(collection_name, deposit)