Skip to content

Add crossmark update policy page deposit functionality#1380

Open
Copilot wants to merge 2 commits intomainfrom
copilot/add-crossmark-policy-deposit
Open

Add crossmark update policy page deposit functionality#1380
Copilot wants to merge 2 commits intomainfrom
copilot/add-crossmark-policy-deposit

Conversation

Copy link
Contributor

Copilot AI commented Mar 6, 2026

Implements the function to build and deposit a CrossRef crossmark update policy page — a publisher's web page (with a registered DOI) that describes how corrections, retractions, and withdrawals are handled.

O que esse PR faz?

  • Adds doi_manager/crossmark.py with two public functions:
    • build_crossmark_policy_page_xml(doi, url, depositor_name, depositor_email_address, registrant) — builds a CrossRef schema 4.4.0 XML batch payload using the <database>/<dataset> structure to register the policy page URL under the given DOI.
    • deposit_crossmark_policy_page(doi, url, login_id, login_passwd, depositor_name, depositor_email_address, registrant, is_test=False) — validates inputs, builds the XML, and POSTs it to the CrossRef deposit API as a multipart upload. Supports is_test to target the test server.
from doi_manager.crossmark import deposit_crossmark_policy_page

response = deposit_crossmark_policy_page(
    doi="10.1234/update-policy",
    url="https://journal.example.org/correction-policy",
    login_id="mylogin",
    login_passwd="mypassword",
    depositor_name="Depositor",
    depositor_email_address="depositor@example.org",
    registrant="Registrant",
    is_test=True,  # use CrossRef test endpoint
)

Onde a revisão poderia começar?

doi_manager/crossmark.py — start with build_crossmark_policy_page_xml, then deposit_crossmark_policy_page.

Como este poderia ser testado manualmente?

  1. Call deposit_crossmark_policy_page(...) with is_test=True and valid CrossRef test credentials, a DOI prefix you own, and the URL of the policy page.
  2. Verify the response is HTTP 200 and check the CrossRef test submission system for the deposit.

Algum cenário de contexto que queira dar?

CrossMark requires publishers to register their update policy page URL as a DOI with CrossRef before they can embed the CrossMark widget in articles. This deposit is separate from article DOI deposits — it uses the <database>/<dataset> XML schema rather than <journal>/<journal_article>.

The depositor_name parameter falls back to registrant when empty/None.

Screenshots

N/A — backend only.

Quais são tickets relevantes?

Referências

Original prompt

This section details on the original issue you should resolve

<issue_title>Criar funcionalidade para registrar a página de política de atualização (crossmark)</issue_title>
<issue_description>Crie uma função que:

  • recebe os argumentos para realizar o depósito da página de política de atualização (crossmark)
  • realize o depósito</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Add functionality to register crossmark policy update page Add crossmark update policy page deposit functionality Mar 6, 2026
@robertatakenaka robertatakenaka marked this pull request as ready for review March 7, 2026 15:23
Copilot AI review requested due to automatic review settings March 7, 2026 15:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds CrossRef CrossMark update policy page deposit functionality to the doi_manager app. It introduces a new crossmark.py module with two public functions — one to build the CrossRef XML payload and one to POST it to the CrossRef deposit API — along with a comprehensive test suite.

Changes:

  • Adds doi_manager/crossmark.py with build_crossmark_policy_page_xml() and deposit_crossmark_policy_page() functions for registering a CrossMark update policy page DOI with CrossRef.
  • Adds doi_manager/tests.py with unit tests covering XML structure and the deposit HTTP call behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
doi_manager/crossmark.py New module with XML builder and HTTP deposit functions for CrossRef CrossMark policy page registration
doi_manager/tests.py New test file covering XML content assertions and HTTP posting behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +145 to +151
xml_tree = ET.ElementTree(doi_batch)
return ET.tostring(
xml_tree,
pretty_print=True,
xml_declaration=True,
encoding="utf-8",
).decode("utf-8")
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ET.tostring() call at line 146 is passed xml_tree, which is an ET.ElementTree instance, not an ET.Element. While lxml's tostring() does accept ElementTree objects, creating the ElementTree wrapper at line 145 is entirely unnecessary here — ET.tostring() can operate directly on the root Element (doi_batch). The intermediate variable xml_tree should be removed and doi_batch should be passed directly to ET.tostring(). This avoids confusion and eliminates an unnecessary allocation.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +131
class DepositCrossmarkPolicyPageTest(TestCase):
def _call(self, **kwargs):
defaults = dict(
doi="10.1234/update-policy",
url="https://example.org/update-policy",
login_id="mylogin",
login_passwd="mypassword",
depositor_name="Test Depositor",
depositor_email_address="depositor@example.org",
registrant="Test Registrant",
)
defaults.update(kwargs)
return deposit_crossmark_policy_page(**defaults)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documented fallback behaviour — where depositor_name falls back to registrant when it is None or empty — is not covered by any test in DepositCrossmarkPolicyPageTest. There should be a test that calls deposit_crossmark_policy_page with depositor_name=None (and depositor_name="") and asserts that the resulting XML's <depositor_name> element contains the value of registrant instead.

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +86
nsmap = {
"xsi": "http://www.w3.org/2001/XMLSchema-instance",
}

doi_batch = ET.Element("doi_batch", nsmap=nsmap)
doi_batch.set("version", "4.4.0")
doi_batch.set("xmlns", "http://www.crossref.org/schema/4.4.0")
doi_batch.set(
"{http://www.w3.org/2001/XMLSchema-instance}schemaLocation",
"http://www.crossref.org/schema/4.4.0 "
"http://www.crossref.org/schemas/crossref4.4.0.xsd",
)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CrossRef default namespace (http://www.crossref.org/schema/4.4.0) is set via doi_batch.set("xmlns", "http://www.crossref.org/schema/4.4.0") (a plain attribute assignment) rather than through lxml's nsmap mechanism. In lxml, a default namespace must be declared by passing None as the key in the nsmap dict when creating the element (e.g., {None: "http://www.crossref.org/schema/4.4.0", "xsi": ...}), and all child elements must also include the full namespace URI in their tag (e.g., ET.SubElement(head, "{http://www.crossref.org/schema/4.4.0}doi_batch_id")).

With the current code, the child elements (head, doi_batch_id, timestamp, body, database, etc.) are created without any namespace, meaning they belong to no namespace. This causes two problems:

  1. The serialized XML will have xmlns as a literal plain attribute rather than a proper namespace declaration; CrossRef's deposit endpoint will likely reject the submission as non-conformant.
  2. The tests that search for elements using the {http://www.crossref.org/schema/4.4.0} namespace prefix (e.g., root.find(f".//{{{ns}}}doi_batch_id")) will return None for all lookups, causing every assertIsNotNone in BuildCrossmarkPolicyPageXMLTest to fail at runtime.

The fix is to include None: "http://www.crossref.org/schema/4.4.0" in nsmap and prefix every ET.SubElement tag with {http://www.crossref.org/schema/4.4.0} (or build all tag strings with the namespace URI), and remove the doi_batch.set("xmlns", ...) call.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Criar funcionalidade para depositar a página de política de atualização (crossmark) no Crossref

3 participants