diff --git a/docs/metadata.rst b/docs/metadata.rst --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -36,7 +36,11 @@ .. code:: xml - www.url-example.com + http://example.com/my_project + +- **the create\_origin** tag *SHOULD* be used to specify the URL of the origin + to create (otherwise, a fallback is created using the slug, or a random + string if missing) - **the description** of the software deposit *SHOULD* be provided [codemeta:description]: short or long description of the software @@ -55,11 +59,17 @@ .. code:: xml - + Awesome Compiler urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2017-10-07T15:17:08Z some awesome author + + + + + Using Atom with CodeMeta @@ -69,9 +79,15 @@ + xmlns:codemeta="https://doi.org/10.5063/SCHEMA/CODEMETA-2.0" + xmlns:swhdeposit="https://www.softwareheritage.org/schema/2018/deposit"> Awesome Compiler urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + + + + + 1785io25c695 origin url other identifier, DOI, ARK @@ -129,9 +145,15 @@ + xmlns:codemeta="https://doi.org/10.5063/SCHEMA/CODEMETA-2.0" + xmlns:swhdeposit="https://www.softwareheritage.org/schema/2018/deposit"> Awesome Compiler urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + + + + + hal-01587361 doi:10.5281/zenodo.438684 The assignment problem diff --git a/docs/specs/metadata_example.xml b/docs/specs/metadata_example.xml --- a/docs/specs/metadata_example.xml +++ b/docs/specs/metadata_example.xml @@ -23,6 +23,9 @@ UPMC + + + diff --git a/docs/specs/spec-loading.rst b/docs/specs/spec-loading.rst --- a/docs/specs/spec-loading.rst +++ b/docs/specs/spec-loading.rst @@ -54,7 +54,8 @@ Origin artifact ~~~~~~~~~~~~~~~ -We create an origin URL by concatenating the client's `provider_url` and the +If the ```` is missing, +we create an origin URL by concatenating the client's `provider_url` and the value of the Slug header of the initial POST request of the deposit (or a randomly generated slug if it is missing). diff --git a/docs/specs/swh.xsd b/docs/specs/swh.xsd --- a/docs/specs/swh.xsd +++ b/docs/specs/swh.xsd @@ -7,6 +7,12 @@ + + + + + + diff --git a/docs/user-manual.rst b/docs/user-manual.rst --- a/docs/user-manual.rst +++ b/docs/user-manual.rst @@ -98,7 +98,8 @@ (deposit)$ cat metadata.xml + xmlns:codemeta="https://doi.org/10.5063/SCHEMA/CODEMETA-2.0" + xmlns:swh="https://www.softwareheritage.org/schema/2018/deposit"> Verifiable online voting system belenios-01243065 https://gitlab.inria.fr/belenios/belenios @@ -119,6 +120,11 @@ Belenios Test User + + + + + (deposit)$ diff --git a/swh/deposit/api/common.py b/swh/deposit/api/common.py --- a/swh/deposit/api/common.py +++ b/swh/deposit/api/common.py @@ -728,7 +728,7 @@ "Please ensure your metadata file is correctly formatted.", ) - if not metadata: + if metadata is None: raise DepositError( BAD_REQUEST, "Empty body request is not supported", @@ -736,18 +736,30 @@ "If the body is empty, there is no metadata.", ) - if ( - "atom:external_identifier" in metadata - and headers.slug - and metadata["atom:external_identifier"] != headers.slug - ): - # TODO: When clients stopped using it, raise this error - # even when they are equal. - raise DepositError( - BAD_REQUEST, - "The 'external_identifier' tag is deprecated, " - "the Slug header should be used instead.", - ) + create_origin = metadata.get("swh:deposit", {}).get("swh:create_origin") + if create_origin: + origin_url = create_origin["swh:origin"]["@url"] + deposit.origin_url = origin_url + + if "atom:external_identifier" in metadata: + # Deprecated tag. + # When clients stopped using it, this should raise an error + # unconditionally + + if deposit.origin_url: + raise DepositError( + BAD_REQUEST, + " is deprecated, you should only use " + " from now on.", + ) + + if headers.slug and metadata["atom:external_identifier"] != headers.slug: + raise DepositError( + BAD_REQUEST, + "The 'external_identifier' tag is deprecated, " + "the Slug header should be used instead.", + ) + # Determine if we are in the metadata-only deposit case try: swhid = parse_swh_reference(metadata) @@ -756,6 +768,16 @@ PARSING_ERROR, "Invalid SWHID reference", str(e), ) + if swhid is not None and ( + deposit.origin_url or deposit.parent or deposit.external_id + ): + raise DepositError( + BAD_REQUEST, + " is for metadata-only deposits and " + " / Slug are for code deposits, " + "only one may be used on a given deposit.", + ) + self._deposit_put( deposit=deposit, in_progress=headers.in_progress, ) diff --git a/swh/deposit/tests/api/test_collection.py b/swh/deposit/tests/api/test_collection.py --- a/swh/deposit/tests/api/test_collection.py +++ b/swh/deposit/tests/api/test_collection.py @@ -105,23 +105,28 @@ def test_add_deposit_when_partial_makes_new_deposit( - authenticated_client, deposit_collection, partial_deposit, atom_dataset + authenticated_client, + deposit_collection, + partial_deposit, + atom_dataset, + deposit_user, ): """Posting deposit on collection when previous is partial makes new deposit """ deposit = partial_deposit assert deposit.status == DEPOSIT_STATUS_PARTIAL + origin_url = deposit_user.provider_url + deposit.external_id # adding a new deposit with the same external id response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data0"] % origin_url, HTTP_SLUG=deposit.external_id, ) - assert response.status_code == status.HTTP_201_CREATED + assert response.status_code == status.HTTP_201_CREATED, response.content.decode() response_content = parse_xml(BytesIO(response.content)) deposit_id = response_content["swh:deposit_id"] @@ -133,7 +138,7 @@ def test_add_deposit_when_failed_makes_new_deposit_with_no_parent( - authenticated_client, deposit_collection, failed_deposit, atom_dataset + authenticated_client, deposit_collection, failed_deposit, atom_dataset, deposit_user ): """Posting deposit on collection when deposit done makes new deposit with parent @@ -141,13 +146,14 @@ """ deposit = failed_deposit assert deposit.status == DEPOSIT_STATUS_LOAD_FAILURE + origin_url = deposit_user.provider_url + deposit.external_id # adding a new deposit with the same external id as a completed deposit # creates the parenting chain response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data0"] % origin_url, HTTP_SLUG=deposit.external_id, ) @@ -163,7 +169,11 @@ def test_add_deposit_when_done_makes_new_deposit_with_parent_old_one( - authenticated_client, deposit_collection, completed_deposit, atom_dataset + authenticated_client, + deposit_collection, + completed_deposit, + atom_dataset, + deposit_user, ): """Posting deposit on collection when deposit done makes new deposit with parent @@ -172,13 +182,14 @@ # given multiple deposit already loaded deposit = completed_deposit assert deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS + origin_url = deposit_user.provider_url + deposit.external_id # adding a new deposit with the same external id as a completed deposit # creates the parenting chain response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data0"] % origin_url, HTTP_SLUG=deposit.external_id, ) @@ -190,7 +201,7 @@ new_deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == new_deposit.collection - assert deposit.external_id == new_deposit.external_id + assert deposit.origin_url == origin_url assert new_deposit != deposit assert new_deposit.parent == deposit @@ -203,12 +214,14 @@ deposit_another_collection, atom_dataset, sample_archive, + deposit_user, ): """Posting a deposit with an external_id conflicting with an external_id of a different client does not create a parent relationship """ external_id = "foobar" + origin_url = deposit_user.provider_url + external_id # create a deposit for that other user, with the same slug other_deposit = create_deposit( @@ -223,7 +236,7 @@ response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data0"] % origin_url, HTTP_SLUG=external_id, ) @@ -246,6 +259,7 @@ completed_deposit, atom_dataset, sample_archive, + deposit_user, ): """Posting a deposit with an external_id conflicting with an external_id of a different client creates a parent relationship with the deposit @@ -255,6 +269,7 @@ # given multiple deposit already loaded deposit = completed_deposit assert deposit.status == DEPOSIT_STATUS_LOAD_SUCCESS + origin_url = deposit_user.provider_url + deposit.external_id # create a deposit for that other user, with the same slug other_deposit = create_deposit( @@ -269,7 +284,7 @@ response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data0"] % origin_url, HTTP_SLUG=deposit.external_id, ) diff --git a/swh/deposit/tests/api/test_collection_post_atom.py b/swh/deposit/tests/api/test_collection_post_atom.py --- a/swh/deposit/tests/api/test_collection_post_atom.py +++ b/swh/deposit/tests/api/test_collection_post_atom.py @@ -34,7 +34,7 @@ ) # then - assert response.status_code == status.HTTP_201_CREATED + assert response.status_code == status.HTTP_201_CREATED, response.content.decode() response_content = parse_xml(BytesIO(response.content)) deposit_id = response_content["swh:deposit_id"] @@ -96,22 +96,52 @@ assert b"Malformed xml metadata" in response.content -def test_post_deposit_atom_no_slug_header( +def test_post_deposit_atom_use_slug_header( authenticated_client, deposit_collection, deposit_user, atom_dataset, mocker ): - """Posting an atom entry without a slug header should generate one + """Posting an atom entry with a slug header but no origin url generates + an origin url from the slug """ url = reverse(COL_IRI, args=[deposit_collection.name]) - id_ = str(uuid.uuid4()) - mocker.patch("uuid.uuid4", return_value=id_) + slug = str(uuid.uuid4()) # when response = authenticated_client.post( url, content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], + data=atom_dataset["entry-data-no-origin-url"], + HTTP_IN_PROGRESS="false", + HTTP_SLUG=slug, + ) + + assert response.status_code == status.HTTP_201_CREATED + response_content = parse_xml(BytesIO(response.content)) + deposit_id = response_content["swh:deposit_id"] + + deposit = Deposit.objects.get(pk=deposit_id) + assert deposit.collection == deposit_collection + assert deposit.origin_url == deposit_user.provider_url + slug + assert deposit.status == DEPOSIT_STATUS_DEPOSITED + + +def test_post_deposit_atom_no_origin_url_nor_slug_header( + authenticated_client, deposit_collection, deposit_user, atom_dataset, mocker +): + """Posting an atom entry without an origin url or a slug header should generate one + + """ + url = reverse(COL_IRI, args=[deposit_collection.name]) + + slug = str(uuid.uuid4()) + mocker.patch("uuid.uuid4", return_value=slug) + + # when + response = authenticated_client.post( + url, + content_type="application/atom+xml;type=entry", + data=atom_dataset["entry-data-no-origin-url"], # + headers HTTP_IN_PROGRESS="false", ) @@ -122,7 +152,7 @@ deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == deposit_collection - assert deposit.origin_url == deposit_user.provider_url + id_ + assert deposit.origin_url == deposit_user.provider_url + slug assert deposit.status == DEPOSIT_STATUS_DEPOSITED @@ -132,13 +162,14 @@ """Posting an atom entry without a slug header should return a 400 """ + external_id = "foobar" url = reverse(COL_IRI, args=[deposit_collection.name]) # when response = authenticated_client.post( url, content_type="application/atom+xml;type=entry", - data=atom_dataset["error-with-external-identifier"], + data=atom_dataset["error-with-external-identifier"] % external_id, # + headers HTTP_IN_PROGRESS="false", HTTP_SLUG="something", @@ -148,6 +179,61 @@ assert response.status_code == status.HTTP_400_BAD_REQUEST +def test_post_deposit_atom_with_create_origin_and_external_identifier( + authenticated_client, deposit_collection, atom_dataset, deposit_user +): + """ was deprecated before + was introduced, clients should get an error when trying to use both + + """ + external_id = "foobar" + origin_url = deposit_user.provider_url + external_id + url = reverse(COL_IRI, args=[deposit_collection.name]) + + document = atom_dataset["error-with-external-identifier-and-create-origin"].format( + external_id=external_id, url=origin_url, + ) + + # when + response = authenticated_client.post( + url, + content_type="application/atom+xml;type=entry", + data=document, + # + headers + HTTP_IN_PROGRESS="false", + ) + + assert b"<external_identifier> is deprecated" in response.content + assert response.status_code == status.HTTP_400_BAD_REQUEST + + +def test_post_deposit_atom_with_create_origin_and_reference( + authenticated_client, deposit_collection, atom_dataset, deposit_user +): + """ and are mutually exclusive + + """ + external_id = "foobar" + origin_url = deposit_user.provider_url + external_id + url = reverse(COL_IRI, args=[deposit_collection.name]) + + document = atom_dataset["error-with-reference-and-create-origin"].format( + external_id=external_id, url=origin_url, + ) + + # when + response = authenticated_client.post( + url, + content_type="application/atom+xml;type=entry", + data=document, + # + headers + HTTP_IN_PROGRESS="false", + ) + + assert b"only one may be used on a given deposit" in response.content + assert response.status_code == status.HTTP_400_BAD_REQUEST + + def test_post_deposit_atom_unknown_collection(authenticated_client, atom_dataset): """Posting an atom entry to an unknown collection should return a 404 @@ -167,37 +253,36 @@ def test_post_deposit_atom_entry_initial( - authenticated_client, deposit_collection, atom_dataset + authenticated_client, deposit_collection, atom_dataset, deposit_user ): """Posting an initial atom entry should return 201 with deposit receipt """ # given - external_id = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a" + origin_url = deposit_user.provider_url + "1225c695-cfb8-4ebb-aaaa-80da344efa6a" with pytest.raises(Deposit.DoesNotExist): - Deposit.objects.get(external_id=external_id) + Deposit.objects.get(origin_url=origin_url) - atom_entry_data = atom_dataset["entry-data0"] + atom_entry_data = atom_dataset["entry-data0"] % origin_url # when response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", data=atom_entry_data, - HTTP_SLUG=external_id, HTTP_IN_PROGRESS="false", ) # then - assert response.status_code == status.HTTP_201_CREATED + assert response.status_code == status.HTTP_201_CREATED, response.content.decode() response_content = parse_xml(BytesIO(response.content)) deposit_id = response_content["swh:deposit_id"] deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == deposit_collection - assert deposit.external_id == external_id + assert deposit.origin_url == origin_url assert deposit.status == DEPOSIT_STATUS_DEPOSITED # one associated request to a deposit @@ -208,24 +293,23 @@ def test_post_deposit_atom_entry_with_codemeta( - authenticated_client, deposit_collection, atom_dataset + authenticated_client, deposit_collection, atom_dataset, deposit_user ): """Posting an initial atom entry should return 201 with deposit receipt """ # given - external_id = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a" + origin_url = deposit_user.provider_url + "1225c695-cfb8-4ebb-aaaa-80da344efa6a" with pytest.raises(Deposit.DoesNotExist): - Deposit.objects.get(external_id=external_id) + Deposit.objects.get(origin_url=origin_url) - atom_entry_data = atom_dataset["codemeta-sample"] + atom_entry_data = atom_dataset["codemeta-sample"] % origin_url # when response = authenticated_client.post( reverse(COL_IRI, args=[deposit_collection.name]), content_type="application/atom+xml;type=entry", data=atom_entry_data, - HTTP_SLUG=external_id, HTTP_IN_PROGRESS="false", ) @@ -238,7 +322,7 @@ deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == deposit_collection - assert deposit.external_id == external_id + assert deposit.origin_url == origin_url assert deposit.status == DEPOSIT_STATUS_DEPOSITED # one associated request to a deposit @@ -249,16 +333,16 @@ def test_post_deposit_atom_entry_multiple_steps( - authenticated_client, deposit_collection, atom_dataset + authenticated_client, deposit_collection, atom_dataset, deposit_user ): """After initial deposit, updating a deposit should return a 201 """ # given - external_id = "urn:uuid:2225c695-cfb8-4ebb-aaaa-80da344efa6a" + origin_url = deposit_user.provider_url + "2225c695-cfb8-4ebb-aaaa-80da344efa6a" with pytest.raises(Deposit.DoesNotExist): - deposit = Deposit.objects.get(external_id=external_id) + deposit = Deposit.objects.get(origin_url=origin_url) # when response = authenticated_client.post( @@ -266,7 +350,6 @@ content_type="application/atom+xml;type=entry", data=atom_dataset["entry-data1"], HTTP_IN_PROGRESS="True", - HTTP_SLUG=external_id, ) # then @@ -277,14 +360,14 @@ deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == deposit_collection - assert deposit.external_id == external_id + assert deposit.origin_url is None # not provided yet assert deposit.status == "partial" # one associated request to a deposit deposit_requests = DepositRequest.objects.filter(deposit=deposit) assert len(deposit_requests) == 1 - atom_entry_data = atom_dataset["entry-data-minimal"] + atom_entry_data = atom_dataset["entry-only-create-origin"] % (origin_url) for link in response_content["atom:link"]: if link["@rel"] == "http://purl.org/net/sword/terms/add": @@ -302,14 +385,14 @@ ) # then - assert response.status_code == status.HTTP_201_CREATED, response.content + assert response.status_code == status.HTTP_201_CREATED, response.content.decode() response_content = parse_xml(BytesIO(response.content)) deposit_id = int(response_content["swh:deposit_id"]) deposit = Deposit.objects.get(pk=deposit_id) assert deposit.collection == deposit_collection - assert deposit.external_id == external_id + assert deposit.origin_url == origin_url assert deposit.status == DEPOSIT_STATUS_DEPOSITED assert len(Deposit.objects.all()) == 1 diff --git a/swh/deposit/tests/api/test_deposit_private_read_metadata.py b/swh/deposit/tests/api/test_deposit_private_read_metadata.py --- a/swh/deposit/tests/api/test_deposit_private_read_metadata.py +++ b/swh/deposit/tests/api/test_deposit_private_read_metadata.py @@ -341,7 +341,10 @@ actual_data = response.json() assert actual_data == { - "origin": {"type": "deposit", "url": None,}, + "origin": { + "type": "deposit", + "url": "https://hal-test.archives-ouvertes.fr/hal-01243065", + }, "metadata_raw": [codemeta_entry_data], "metadata_dict": parse_xml(codemeta_entry_data), "provider": { diff --git a/swh/deposit/tests/api/test_deposit_update.py b/swh/deposit/tests/api/test_deposit_update.py --- a/swh/deposit/tests/api/test_deposit_update.py +++ b/swh/deposit/tests/api/test_deposit_update.py @@ -12,6 +12,7 @@ from swh.deposit.api.common import ACCEPT_ARCHIVE_CONTENT_TYPES from swh.deposit.config import ( + COL_IRI, DEPOSIT_STATUS_DEPOSITED, DEPOSIT_STATUS_PARTIAL, EDIT_IRI, @@ -105,13 +106,15 @@ partial_deposit_with_metadata, deposit_collection, atom_dataset, + deposit_user, ): """Replace all metadata with another one should return a 204 response """ # given deposit = partial_deposit_with_metadata - raw_metadata0 = atom_dataset["entry-data0"] + origin_url = deposit_user.provider_url + deposit.external_id + raw_metadata0 = atom_dataset["entry-data0"] % origin_url requests_meta = DepositRequest.objects.filter(deposit=deposit, type="metadata") assert len(requests_meta) == 1 @@ -210,11 +213,13 @@ deposit_collection, partial_deposit_with_metadata, atom_dataset, + deposit_user, ): """Add metadata with another one should return a 204 response """ deposit = partial_deposit_with_metadata + origin_url = deposit_user.provider_url + deposit.external_id requests = DepositRequest.objects.filter(deposit=deposit, type="metadata") assert len(requests) == 1 @@ -236,7 +241,7 @@ ) assert len(requests) == 2 - expected_raw_meta0 = atom_dataset["entry-data0"] + expected_raw_meta0 = atom_dataset["entry-data0"] % origin_url # a new one was added assert requests[0].raw_metadata == expected_raw_meta0 assert requests[1].raw_metadata == atom_entry @@ -253,6 +258,7 @@ partial_deposit_with_metadata, atom_dataset, sample_archive, + deposit_user, ): """Scenario: Add both a new archive and new metadata to a partial deposit is ok @@ -260,6 +266,7 @@ """ deposit = partial_deposit_with_metadata + origin_url = deposit_user.provider_url + deposit.external_id requests = DepositRequest.objects.filter(deposit=deposit, type="metadata") assert len(requests) == 1 @@ -299,7 +306,7 @@ ) assert len(requests) == 1 + 1, "New deposit request archive got added" - expected_raw_meta0 = atom_dataset["entry-data0"] + expected_raw_meta0 = atom_dataset["entry-data0"] % origin_url # a new one was added assert requests[0].raw_metadata == expected_raw_meta0 assert requests[1].raw_metadata == data_atom_entry @@ -508,6 +515,7 @@ deposit_collection, atom_dataset, sample_archive, + deposit_user, ): """Scenario: Replace metadata and archive(s) with new ones should be ok @@ -516,7 +524,8 @@ """ # given deposit = partial_deposit_with_metadata - raw_metadata0 = atom_dataset["entry-data0"] + origin_url = deposit_user.provider_url + deposit.external_id + raw_metadata0 = atom_dataset["entry-data0"] % origin_url requests_meta = DepositRequest.objects.filter(deposit=deposit, type="metadata") assert len(requests_meta) == 1 @@ -792,3 +801,84 @@ b"- Mandatory alternate fields are missing (atom:name or atom:title)" in response.content ) + + +def test_put_atom_with_create_origin_and_external_identifier( + authenticated_client, deposit_collection, atom_dataset, deposit_user +): + """ was deprecated before + was introduced, clients should get an error when trying to use both + + """ + external_id = "foobar" + origin_url = deposit_user.provider_url + external_id + url = reverse(COL_IRI, args=[deposit_collection.name]) + + response = authenticated_client.post( + url, + content_type="application/atom+xml;type=entry", + data=atom_dataset["entry-data0"] % origin_url, + HTTP_IN_PROGRESS="true", + ) + + assert response.status_code == status.HTTP_201_CREATED + response_content = parse_xml(BytesIO(response.content)) + + for link in response_content["atom:link"]: + if link["@rel"] == "edit": + edit_iri = link["@href"] + break + else: + assert False, response_content + + # when + response = authenticated_client.put( + edit_iri, + content_type="application/atom+xml;type=entry", + data=atom_dataset["error-with-external-identifier"] % external_id, + # + headers + HTTP_IN_PROGRESS="false", + ) + + assert b"<external_identifier> is deprecated" in response.content + assert response.status_code == status.HTTP_400_BAD_REQUEST + + +def test_put_atom_with_create_origin_and_reference( + authenticated_client, deposit_collection, atom_dataset, deposit_user +): + """ and are mutually exclusive + + """ + external_id = "foobar" + origin_url = deposit_user.provider_url + external_id + url = reverse(COL_IRI, args=[deposit_collection.name]) + + response = authenticated_client.post( + url, + content_type="application/atom+xml;type=entry", + data=atom_dataset["entry-data0"] % origin_url, + HTTP_IN_PROGRESS="true", + ) + + assert response.status_code == status.HTTP_201_CREATED + response_content = parse_xml(BytesIO(response.content)) + + for link in response_content["atom:link"]: + if link["@rel"] == "edit": + edit_iri = link["@href"] + break + else: + assert False, response_content + + # when + response = authenticated_client.put( + edit_iri, + content_type="application/atom+xml;type=entry", + data=atom_dataset["entry-data-with-origin-reference"].format(url=origin_url), + # + headers + HTTP_IN_PROGRESS="false", + ) + + assert b"only one may be used on a given deposit" in response.content + assert response.status_code == status.HTTP_400_BAD_REQUEST diff --git a/swh/deposit/tests/conftest.py b/swh/deposit/tests/conftest.py --- a/swh/deposit/tests/conftest.py +++ b/swh/deposit/tests/conftest.py @@ -347,11 +347,12 @@ **kwargs, ) + origin_url = deposit.client.provider_url + deposit.external_id + response = authenticated_client.post( reverse(SE_IRI, args=[collection_name, deposit.id]), content_type="application/atom+xml;type=entry", - data=atom_dataset["entry-data0"], - HTTP_SLUG=deposit.external_id, + data=atom_dataset["entry-data0"] % origin_url, HTTP_IN_PROGRESS="true", ) diff --git a/swh/deposit/tests/data/atom/codemeta-sample.xml b/swh/deposit/tests/data/atom/codemeta-sample.xml --- a/swh/deposit/tests/data/atom/codemeta-sample.xml +++ b/swh/deposit/tests/data/atom/codemeta-sample.xml @@ -1,7 +1,13 @@ + + + + + hal-01587361 https://hal.inria.fr/hal-01587361 https://hal.inria.fr/hal-01587361/document diff --git a/swh/deposit/tests/data/atom/entry-data0.xml b/swh/deposit/tests/data/atom/entry-data-no-origin-url.xml copy from swh/deposit/tests/data/atom/entry-data0.xml copy to swh/deposit/tests/data/atom/entry-data-no-origin-url.xml --- a/swh/deposit/tests/data/atom/entry-data0.xml +++ b/swh/deposit/tests/data/atom/entry-data-no-origin-url.xml @@ -1,5 +1,6 @@ - + Awesome Compiler urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2017-10-07T15:17:08Z @@ -22,3 +23,4 @@ running all + diff --git a/swh/deposit/tests/data/atom/entry-data-with-origin-reference.xml b/swh/deposit/tests/data/atom/entry-data-with-origin-reference.xml new file mode 100644 --- /dev/null +++ b/swh/deposit/tests/data/atom/entry-data-with-origin-reference.xml @@ -0,0 +1,13 @@ + + + Awesome Compiler + urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a + dudess + + + + + + diff --git a/swh/deposit/tests/data/atom/entry-data0.xml b/swh/deposit/tests/data/atom/entry-data0.xml --- a/swh/deposit/tests/data/atom/entry-data0.xml +++ b/swh/deposit/tests/data/atom/entry-data0.xml @@ -1,5 +1,6 @@ - + Awesome Compiler urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a 2017-10-07T15:17:08Z @@ -21,4 +22,10 @@ 0.0.1 running all + + + + + + diff --git a/swh/deposit/tests/data/atom/entry-data2.xml b/swh/deposit/tests/data/atom/entry-data2.xml --- a/swh/deposit/tests/data/atom/entry-data2.xml +++ b/swh/deposit/tests/data/atom/entry-data2.xml @@ -1,5 +1,12 @@ - + https://hal-test.archives-ouvertes.fr/some-external-id some awesome author + + + + + + diff --git a/swh/deposit/tests/data/atom/entry-only-create-origin.xml b/swh/deposit/tests/data/atom/entry-only-create-origin.xml new file mode 100644 --- /dev/null +++ b/swh/deposit/tests/data/atom/entry-only-create-origin.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/swh/deposit/tests/data/atom/error-with-decimal.xml b/swh/deposit/tests/data/atom/error-with-decimal.xml --- a/swh/deposit/tests/data/atom/error-with-decimal.xml +++ b/swh/deposit/tests/data/atom/error-with-decimal.xml @@ -1,5 +1,7 @@ - + Composing a Web of Audio Applications hal-01243065 https://hal-test.archives-ouvertes.fr/hal-01243065 @@ -33,4 +35,10 @@ someone@nice.fr FFJ + + + + + + diff --git a/swh/deposit/tests/data/atom/error-with-external-identifier-and-create-origin.xml b/swh/deposit/tests/data/atom/error-with-external-identifier-and-create-origin.xml new file mode 100644 --- /dev/null +++ b/swh/deposit/tests/data/atom/error-with-external-identifier-and-create-origin.xml @@ -0,0 +1,14 @@ + + + Composing a Web of Audio Applications + hal-01243065 + {external_id} + someone + + + + + + diff --git a/swh/deposit/tests/data/atom/error-with-external-identifier.xml b/swh/deposit/tests/data/atom/error-with-external-identifier.xml --- a/swh/deposit/tests/data/atom/error-with-external-identifier.xml +++ b/swh/deposit/tests/data/atom/error-with-external-identifier.xml @@ -2,5 +2,6 @@ Composing a Web of Audio Applications hal-01243065 - hal-01243065 + someone + %s diff --git a/swh/deposit/tests/data/atom/error-with-reference-and-create-origin.xml b/swh/deposit/tests/data/atom/error-with-reference-and-create-origin.xml new file mode 100644 --- /dev/null +++ b/swh/deposit/tests/data/atom/error-with-reference-and-create-origin.xml @@ -0,0 +1,16 @@ + + + Composing a Web of Audio Applications + hal-01243065 + someone + + + + + + + + + diff --git a/swh/deposit/tests/data/atom/metadata.xml b/swh/deposit/tests/data/atom/metadata.xml --- a/swh/deposit/tests/data/atom/metadata.xml +++ b/swh/deposit/tests/data/atom/metadata.xml @@ -1,6 +1,7 @@ + xmlns:codemeta="https://doi.org/10.5063/SCHEMA/CODEMETA-2.0" + xmlns:swh="https://www.softwareheritage.org/schema/2018/deposit"> Composing a Web of Audio Applications hal-01243065 https://hal-test.archives-ouvertes.fr/hal-01243065 @@ -26,5 +27,12 @@ Morane Gruenpeter + + + + + + + %s