From cbba553b4960173076c54f5486a64b62b6447cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pasternak?= Date: Fri, 27 Mar 2026 22:53:03 +0100 Subject: [PATCH 1/3] Add 'Create and add to PBN export queue' button to publication importer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes ticket #317. Adds a second green button next to the existing "Utwórz publikację" button in the publication importer review step. The button appears when PBN integration is enabled (pbn_integracja and pbn_aktualizuj_na_biezaco on Uczelnia). Clicking it creates the publication and immediately queues it for PBN export via the existing sprobuj_utworzyc_zlecenie_eksportu_do_PBN_gui helper. Also adds Django messages display to the done step for HTMX partial responses. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../partials/step_done.html | 11 ++++++++++ .../partials/step_review.html | 8 +++++++ src/importer_publikacji/views.py | 21 ++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/importer_publikacji/templates/importer_publikacji/partials/step_done.html b/src/importer_publikacji/templates/importer_publikacji/partials/step_done.html index 9abf37779..b7b9ba356 100644 --- a/src/importer_publikacji/templates/importer_publikacji/partials/step_done.html +++ b/src/importer_publikacji/templates/importer_publikacji/partials/step_done.html @@ -1,3 +1,14 @@ +{% if messages %} + {% for message in messages %} +
+ {{ message|safe }} +
+ {% endfor %} +{% endif %} {% if error %}

diff --git a/src/importer_publikacji/templates/importer_publikacji/partials/step_review.html b/src/importer_publikacji/templates/importer_publikacji/partials/step_review.html index fe299c00b..3cd1b55f0 100644 --- a/src/importer_publikacji/templates/importer_publikacji/partials/step_review.html +++ b/src/importer_publikacji/templates/importer_publikacji/partials/step_review.html @@ -220,6 +220,14 @@

Autorzy do przypisania ({{ authors|length }})
Utwórz publikację + {% if show_save_and_pbn %} + + {% endif %}
Date: Sat, 28 Mar 2026 11:00:04 +0100 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20automatyczne=20sprawdzanie=20duplik?= =?UTF-8?q?at=C3=B3w=20w=20PBN=20przy=20imporcie=20publikacji=20(#318)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Przy imporcie z CrossRef/BibTeX/DSpace/WWW system automatycznie sprawdza PBN API po DOI. W kroku weryfikacji wyświetla PBN UID z linkiem, komunikat o braku autoryzacji lub błąd serwisu. Przy tworzeniu rekordu próbuje powiązać go z PBN UID. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../partials/step_verify.html | 34 ++++ .../tests/test_pbn_check.py | 171 ++++++++++++++++++ src/importer_publikacji/views.py | 146 ++++++++++++++- 3 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 src/importer_publikacji/tests/test_pbn_check.py diff --git a/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html b/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html index c0c378a72..226929010 100644 --- a/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html +++ b/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html @@ -22,6 +22,40 @@

{% endif %} + {% if pbn_result %} + {% if pbn_result.pbn_mongo_id %} + + {% elif pbn_result.pbn_needs_auth %} +
+ + Nie można sprawdzić duplikatu + w PBN — wymagana autoryzacja. + Zaloguj się do PBN w menu głównym. +
+ {% elif pbn_result.pbn_error %} +
+ + {{ pbn_result.pbn_error }} +
+ {% endif %} + {% endif %} + {% if suggest_crossref %}
diff --git a/src/importer_publikacji/tests/test_pbn_check.py b/src/importer_publikacji/tests/test_pbn_check.py new file mode 100644 index 000000000..5ffcb6aad --- /dev/null +++ b/src/importer_publikacji/tests/test_pbn_check.py @@ -0,0 +1,171 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from importer_publikacji.views import ( + _check_pbn_by_doi, + _empty_pbn_result, + _get_pbn_publication_by_doi, + _link_pbn_uid, + _populate_pbn_result, +) +from pbn_api.exceptions import ( + AccessDeniedException, + HttpException, + NeedsPBNAuthorisationException, + PraceSerwisoweException, +) + + +def _make_session( + provider_name="CrossRef", + doi="10.1234/test", + matched_data=None, +): + session = MagicMock() + session.provider_name = provider_name + session.normalized_data = {"doi": doi} if doi else {} + session.matched_data = matched_data or {} + return session + + +def test_check_pbn_skip_when_provider_is_pbn(): + session = _make_session(provider_name="PBN") + assert _check_pbn_by_doi(session) is None + + +def test_check_pbn_skip_when_no_doi(): + session = _make_session(doi=None) + assert _check_pbn_by_doi(session) is None + + +def test_check_pbn_skip_when_empty_doi(): + session = _make_session(doi="") + assert _check_pbn_by_doi(session) is None + + +@patch("importer_publikacji.views._get_pbn_client") +def test_check_pbn_skip_when_client_fails(mock_import): + mock_import.side_effect = ValueError("Brak konfiguracji") + with patch( + "importer_publikacji.views._get_pbn_client", + side_effect=ValueError("Brak konfiguracji"), + ): + with patch( + "importer_publikacji.providers.pbn._get_pbn_client", + side_effect=ValueError("Brak konfiguracji"), + ): + session = _make_session() + assert _check_pbn_by_doi(session) is None + + +def test_get_pbn_publication_by_doi_success(): + client = MagicMock() + client.get_publication_by_doi.return_value = { + "mongoId": "abc123def456", + "status": "ACTIVE", + } + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data == {"mongoId": "abc123def456", "status": "ACTIVE"} + assert error is None + + +def test_get_pbn_publication_by_doi_404(): + client = MagicMock() + client.get_publication_by_doi.side_effect = HttpException( + 404, "/api/v1/publications/doi/", "Not found" + ) + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data is None + assert error is not None + assert error["pbn_error"] is None + assert error["pbn_needs_auth"] is False + + +def test_get_pbn_publication_by_doi_access_denied(): + client = MagicMock() + client.get_publication_by_doi.side_effect = AccessDeniedException( + "/api/v1/", "Forbidden" + ) + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data is None + assert error["pbn_needs_auth"] is True + + +def test_get_pbn_publication_by_doi_needs_auth(): + client = MagicMock() + client.get_publication_by_doi.side_effect = NeedsPBNAuthorisationException( + 403, "/api/", "Auth" + ) + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data is None + assert error["pbn_needs_auth"] is True + + +def test_get_pbn_publication_by_doi_prace_serwisowe(): + client = MagicMock() + client.get_publication_by_doi.side_effect = PraceSerwisoweException() + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data is None + assert error["pbn_error"] == "PBN w trakcie prac serwisowych" + + +def test_get_pbn_publication_by_doi_http_500(): + client = MagicMock() + client.get_publication_by_doi.side_effect = HttpException( + 500, "/api/", "Server Error" + ) + data, error = _get_pbn_publication_by_doi(client, "10.1234/test") + assert data is None + assert "Błąd komunikacji z PBN" in error["pbn_error"] + + +def test_empty_pbn_result(): + result = _empty_pbn_result() + assert result["pbn_mongo_id"] is None + assert result["pbn_url"] is None + assert result["pbn_error"] is None + assert result["pbn_needs_auth"] is False + + +@pytest.mark.django_db +def test_populate_pbn_result_with_data(): + session = _make_session() + result = _empty_pbn_result() + data = {"mongoId": "abc123def456", "status": "ACTIVE"} + + _populate_pbn_result(result, data, session) + + assert result["pbn_mongo_id"] == "abc123def456" + assert session.matched_data["pbn_mongo_id"] == "abc123def456" + session.save.assert_called_once() + + +def test_populate_pbn_result_with_empty_data(): + session = _make_session() + result = _empty_pbn_result() + _populate_pbn_result(result, None, session) + assert result["pbn_mongo_id"] is None + + +def test_populate_pbn_result_no_mongo_id(): + session = _make_session() + result = _empty_pbn_result() + _populate_pbn_result(result, {"status": "ACTIVE"}, session) + assert result["pbn_mongo_id"] is None + + +@pytest.mark.django_db +def test_link_pbn_uid_no_mongo_id(): + session = _make_session(matched_data={}) + record = MagicMock() + _link_pbn_uid(session, record) + record.save.assert_not_called() + + +@pytest.mark.django_db +def test_link_pbn_uid_publication_not_found(): + session = _make_session(matched_data={"pbn_mongo_id": "nonexistent123456789012"}) + record = MagicMock() + _link_pbn_uid(session, record) + record.save.assert_not_called() diff --git a/src/importer_publikacji/views.py b/src/importer_publikacji/views.py index fd10d7f3e..4ffc1d9bb 100644 --- a/src/importer_publikacji/views.py +++ b/src/importer_publikacji/views.py @@ -1,4 +1,5 @@ import json +import logging import traceback from django.contrib.contenttypes.models import ContentType @@ -46,6 +47,8 @@ get_providers_metadata, ) +logger = logging.getLogger(__name__) + _POLISH_DIACRITICS = set("ąćęłńóśźżĄĆĘŁŃÓŚŹŻ") @@ -775,6 +778,113 @@ def _find_duplicates(session): return results +def _get_pbn_publication_by_doi(client, doi): + """Wywołaj API PBN i zwróć (data, result) lub result przy błędzie. + + Zwraca krotkę (data, None) przy sukcesie lub + (None, result_dict) przy błędzie wymagającym + natychmiastowego zwrotu. + """ + from pbn_api.exceptions import ( + AccessDeniedException, + HttpException, + NeedsPBNAuthorisationException, + PraceSerwisoweException, + ) + + result = _empty_pbn_result() + + try: + data = client.get_publication_by_doi(doi) + except ( + AccessDeniedException, + NeedsPBNAuthorisationException, + ): + result["pbn_needs_auth"] = True + return None, result + except PraceSerwisoweException: + result["pbn_error"] = "PBN w trakcie prac serwisowych" + return None, result + except HttpException as e: + if getattr(e, "status_code", None) == 404: + return None, result + result["pbn_error"] = f"Błąd komunikacji z PBN: {e}" + return None, result + except Exception as e: + logger.warning("Błąd sprawdzania PBN: %s", e) + result["pbn_error"] = f"Błąd sprawdzania PBN: {e}" + return None, result + + return data, None + + +def _empty_pbn_result(): + """Zwróć pusty słownik wyniku sprawdzenia PBN.""" + return { + "pbn_mongo_id": None, + "pbn_url": None, + "pbn_error": None, + "pbn_needs_auth": False, + } + + +def _populate_pbn_result(result, data, session): + """Wypełnij result danymi z odpowiedzi PBN API.""" + if not (data and isinstance(data, dict)): + return + + mongo_id = data.get("mongoId") + if not mongo_id: + return + + result["pbn_mongo_id"] = mongo_id + uczelnia = Uczelnia.objects.get_default() + if uczelnia and uczelnia.pbn_api_root: + from bpp.const import LINK_PBN_DO_PUBLIKACJI + + result["pbn_url"] = LINK_PBN_DO_PUBLIKACJI.format( + pbn_api_root=uczelnia.pbn_api_root, + pbn_uid_id=mongo_id, + ) + session.matched_data["pbn_mongo_id"] = mongo_id + session.save(update_fields=["matched_data"]) + + +def _check_pbn_by_doi(session): + """Sprawdź czy publikacja z danym DOI istnieje w PBN. + + Zwraca dict z kluczami pbn_mongo_id, pbn_url, + pbn_error, pbn_needs_auth — lub None jeśli sprawdzenie + nie dotyczy (brak DOI, provider PBN, brak konfiguracji). + """ + if session.provider_name == "PBN": + return None + + doi = session.normalized_data.get("doi") + if not doi: + return None + + normalized = normalize_doi(doi) + if not normalized: + return None + + try: + from .providers.pbn import _get_pbn_client + + client = _get_pbn_client() + except Exception as e: + logger.warning("Nie można utworzyć klienta PBN: %s", e) + return None + + data, error_result = _get_pbn_publication_by_doi(client, normalized) + if error_result is not None: + return error_result + + result = _empty_pbn_result() + _populate_pbn_result(result, data, session) + return result + + def _is_crossref_data(raw_data): """Heurystyka: czy raw_data to JSON z CrossRef API.""" if not raw_data or not isinstance(raw_data, dict): @@ -802,6 +912,7 @@ def _verify_context(request, session, form=None): form = VerifyForm(initial=initial) existing = _find_duplicates(session) + pbn_result = _check_pbn_by_doi(session) doi = session.normalized_data.get("doi") suggest_crossref = bool(doi and session.provider_name != "CrossRef") @@ -834,6 +945,7 @@ def _verify_context(request, session, form=None): "auto_zwarte": (mapper.jest_wydawnictwem_zwartym if mapper else None), "suggest_crossref": suggest_crossref, "crossref_doi": doi if suggest_crossref else None, + "pbn_result": pbn_result, "field_categories": field_categories, "raw_json_pretty": raw_json_pretty, } @@ -1273,6 +1385,34 @@ def _create_streszczenia(session, record): ) +def _link_pbn_uid(session, record): + """Powiąż PBN UID z rekordem publikacji, jeśli znaleziono.""" + pbn_mongo_id = session.matched_data.get("pbn_mongo_id") + if not pbn_mongo_id: + return + + from django.db import IntegrityError + + from pbn_api.models import Publication + + try: + pbn_pub = Publication.objects.get( + mongoId=pbn_mongo_id, + ) + record.pbn_uid = pbn_pub + record.save(update_fields=["pbn_uid_id"]) + except Publication.DoesNotExist: + logger.info( + "Rekord PBN %s nie istnieje lokalnie — pominięto linkowanie", + pbn_mongo_id, + ) + except IntegrityError: + logger.warning( + "PBN UID %s jest już powiązany z innym rekordem BPP", + pbn_mongo_id, + ) + + @transaction.atomic def _create_publication(session): """Utwórz rekord publikacji na podstawie sesji.""" @@ -1316,10 +1456,14 @@ def _create_publication(session): _create_streszczenia(session, record) if session.zrodlo and normalized_data.get("year"): - from bpp.models.zrodlo import uzupelnij_punktacje_z_zrodla + from bpp.models.zrodlo import ( + uzupelnij_punktacje_z_zrodla, + ) uzupelnij_punktacje_z_zrodla(record, session.zrodlo, normalized_data["year"]) + _link_pbn_uid(session, record) + return record From 137a6be6ffac334c416f1fcbecd24adf69666e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pasternak?= Date: Sat, 28 Mar 2026 11:03:19 +0100 Subject: [PATCH 3/3] =?UTF-8?q?Revert=20"feat:=20automatyczne=20sprawdzani?= =?UTF-8?q?e=20duplikat=C3=B3w=20w=20PBN=20przy=20imporcie=20publikacji=20?= =?UTF-8?q?(#318)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3974b4677fa755ba158c0b7700c43753b3a893bf. --- .../partials/step_verify.html | 34 ---- .../tests/test_pbn_check.py | 171 ------------------ src/importer_publikacji/views.py | 146 +-------------- 3 files changed, 1 insertion(+), 350 deletions(-) delete mode 100644 src/importer_publikacji/tests/test_pbn_check.py diff --git a/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html b/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html index 226929010..c0c378a72 100644 --- a/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html +++ b/src/importer_publikacji/templates/importer_publikacji/partials/step_verify.html @@ -22,40 +22,6 @@

{% endif %} - {% if pbn_result %} - {% if pbn_result.pbn_mongo_id %} -
- - Znaleziono rekord w PBN: - Publikacja o tym DOI istnieje już - w Polskiej Bibliografii Naukowej. -
- PBN UID: - {{ pbn_result.pbn_mongo_id }} - {% if pbn_result.pbn_url %} - — - - Otwórz w PBN - - {% endif %} -
- {% elif pbn_result.pbn_needs_auth %} -
- - Nie można sprawdzić duplikatu - w PBN — wymagana autoryzacja. - Zaloguj się do PBN w menu głównym. -
- {% elif pbn_result.pbn_error %} -
- - {{ pbn_result.pbn_error }} -
- {% endif %} - {% endif %} - {% if suggest_crossref %}
diff --git a/src/importer_publikacji/tests/test_pbn_check.py b/src/importer_publikacji/tests/test_pbn_check.py deleted file mode 100644 index 5ffcb6aad..000000000 --- a/src/importer_publikacji/tests/test_pbn_check.py +++ /dev/null @@ -1,171 +0,0 @@ -from unittest.mock import MagicMock, patch - -import pytest - -from importer_publikacji.views import ( - _check_pbn_by_doi, - _empty_pbn_result, - _get_pbn_publication_by_doi, - _link_pbn_uid, - _populate_pbn_result, -) -from pbn_api.exceptions import ( - AccessDeniedException, - HttpException, - NeedsPBNAuthorisationException, - PraceSerwisoweException, -) - - -def _make_session( - provider_name="CrossRef", - doi="10.1234/test", - matched_data=None, -): - session = MagicMock() - session.provider_name = provider_name - session.normalized_data = {"doi": doi} if doi else {} - session.matched_data = matched_data or {} - return session - - -def test_check_pbn_skip_when_provider_is_pbn(): - session = _make_session(provider_name="PBN") - assert _check_pbn_by_doi(session) is None - - -def test_check_pbn_skip_when_no_doi(): - session = _make_session(doi=None) - assert _check_pbn_by_doi(session) is None - - -def test_check_pbn_skip_when_empty_doi(): - session = _make_session(doi="") - assert _check_pbn_by_doi(session) is None - - -@patch("importer_publikacji.views._get_pbn_client") -def test_check_pbn_skip_when_client_fails(mock_import): - mock_import.side_effect = ValueError("Brak konfiguracji") - with patch( - "importer_publikacji.views._get_pbn_client", - side_effect=ValueError("Brak konfiguracji"), - ): - with patch( - "importer_publikacji.providers.pbn._get_pbn_client", - side_effect=ValueError("Brak konfiguracji"), - ): - session = _make_session() - assert _check_pbn_by_doi(session) is None - - -def test_get_pbn_publication_by_doi_success(): - client = MagicMock() - client.get_publication_by_doi.return_value = { - "mongoId": "abc123def456", - "status": "ACTIVE", - } - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data == {"mongoId": "abc123def456", "status": "ACTIVE"} - assert error is None - - -def test_get_pbn_publication_by_doi_404(): - client = MagicMock() - client.get_publication_by_doi.side_effect = HttpException( - 404, "/api/v1/publications/doi/", "Not found" - ) - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data is None - assert error is not None - assert error["pbn_error"] is None - assert error["pbn_needs_auth"] is False - - -def test_get_pbn_publication_by_doi_access_denied(): - client = MagicMock() - client.get_publication_by_doi.side_effect = AccessDeniedException( - "/api/v1/", "Forbidden" - ) - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data is None - assert error["pbn_needs_auth"] is True - - -def test_get_pbn_publication_by_doi_needs_auth(): - client = MagicMock() - client.get_publication_by_doi.side_effect = NeedsPBNAuthorisationException( - 403, "/api/", "Auth" - ) - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data is None - assert error["pbn_needs_auth"] is True - - -def test_get_pbn_publication_by_doi_prace_serwisowe(): - client = MagicMock() - client.get_publication_by_doi.side_effect = PraceSerwisoweException() - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data is None - assert error["pbn_error"] == "PBN w trakcie prac serwisowych" - - -def test_get_pbn_publication_by_doi_http_500(): - client = MagicMock() - client.get_publication_by_doi.side_effect = HttpException( - 500, "/api/", "Server Error" - ) - data, error = _get_pbn_publication_by_doi(client, "10.1234/test") - assert data is None - assert "Błąd komunikacji z PBN" in error["pbn_error"] - - -def test_empty_pbn_result(): - result = _empty_pbn_result() - assert result["pbn_mongo_id"] is None - assert result["pbn_url"] is None - assert result["pbn_error"] is None - assert result["pbn_needs_auth"] is False - - -@pytest.mark.django_db -def test_populate_pbn_result_with_data(): - session = _make_session() - result = _empty_pbn_result() - data = {"mongoId": "abc123def456", "status": "ACTIVE"} - - _populate_pbn_result(result, data, session) - - assert result["pbn_mongo_id"] == "abc123def456" - assert session.matched_data["pbn_mongo_id"] == "abc123def456" - session.save.assert_called_once() - - -def test_populate_pbn_result_with_empty_data(): - session = _make_session() - result = _empty_pbn_result() - _populate_pbn_result(result, None, session) - assert result["pbn_mongo_id"] is None - - -def test_populate_pbn_result_no_mongo_id(): - session = _make_session() - result = _empty_pbn_result() - _populate_pbn_result(result, {"status": "ACTIVE"}, session) - assert result["pbn_mongo_id"] is None - - -@pytest.mark.django_db -def test_link_pbn_uid_no_mongo_id(): - session = _make_session(matched_data={}) - record = MagicMock() - _link_pbn_uid(session, record) - record.save.assert_not_called() - - -@pytest.mark.django_db -def test_link_pbn_uid_publication_not_found(): - session = _make_session(matched_data={"pbn_mongo_id": "nonexistent123456789012"}) - record = MagicMock() - _link_pbn_uid(session, record) - record.save.assert_not_called() diff --git a/src/importer_publikacji/views.py b/src/importer_publikacji/views.py index 4ffc1d9bb..fd10d7f3e 100644 --- a/src/importer_publikacji/views.py +++ b/src/importer_publikacji/views.py @@ -1,5 +1,4 @@ import json -import logging import traceback from django.contrib.contenttypes.models import ContentType @@ -47,8 +46,6 @@ get_providers_metadata, ) -logger = logging.getLogger(__name__) - _POLISH_DIACRITICS = set("ąćęłńóśźżĄĆĘŁŃÓŚŹŻ") @@ -778,113 +775,6 @@ def _find_duplicates(session): return results -def _get_pbn_publication_by_doi(client, doi): - """Wywołaj API PBN i zwróć (data, result) lub result przy błędzie. - - Zwraca krotkę (data, None) przy sukcesie lub - (None, result_dict) przy błędzie wymagającym - natychmiastowego zwrotu. - """ - from pbn_api.exceptions import ( - AccessDeniedException, - HttpException, - NeedsPBNAuthorisationException, - PraceSerwisoweException, - ) - - result = _empty_pbn_result() - - try: - data = client.get_publication_by_doi(doi) - except ( - AccessDeniedException, - NeedsPBNAuthorisationException, - ): - result["pbn_needs_auth"] = True - return None, result - except PraceSerwisoweException: - result["pbn_error"] = "PBN w trakcie prac serwisowych" - return None, result - except HttpException as e: - if getattr(e, "status_code", None) == 404: - return None, result - result["pbn_error"] = f"Błąd komunikacji z PBN: {e}" - return None, result - except Exception as e: - logger.warning("Błąd sprawdzania PBN: %s", e) - result["pbn_error"] = f"Błąd sprawdzania PBN: {e}" - return None, result - - return data, None - - -def _empty_pbn_result(): - """Zwróć pusty słownik wyniku sprawdzenia PBN.""" - return { - "pbn_mongo_id": None, - "pbn_url": None, - "pbn_error": None, - "pbn_needs_auth": False, - } - - -def _populate_pbn_result(result, data, session): - """Wypełnij result danymi z odpowiedzi PBN API.""" - if not (data and isinstance(data, dict)): - return - - mongo_id = data.get("mongoId") - if not mongo_id: - return - - result["pbn_mongo_id"] = mongo_id - uczelnia = Uczelnia.objects.get_default() - if uczelnia and uczelnia.pbn_api_root: - from bpp.const import LINK_PBN_DO_PUBLIKACJI - - result["pbn_url"] = LINK_PBN_DO_PUBLIKACJI.format( - pbn_api_root=uczelnia.pbn_api_root, - pbn_uid_id=mongo_id, - ) - session.matched_data["pbn_mongo_id"] = mongo_id - session.save(update_fields=["matched_data"]) - - -def _check_pbn_by_doi(session): - """Sprawdź czy publikacja z danym DOI istnieje w PBN. - - Zwraca dict z kluczami pbn_mongo_id, pbn_url, - pbn_error, pbn_needs_auth — lub None jeśli sprawdzenie - nie dotyczy (brak DOI, provider PBN, brak konfiguracji). - """ - if session.provider_name == "PBN": - return None - - doi = session.normalized_data.get("doi") - if not doi: - return None - - normalized = normalize_doi(doi) - if not normalized: - return None - - try: - from .providers.pbn import _get_pbn_client - - client = _get_pbn_client() - except Exception as e: - logger.warning("Nie można utworzyć klienta PBN: %s", e) - return None - - data, error_result = _get_pbn_publication_by_doi(client, normalized) - if error_result is not None: - return error_result - - result = _empty_pbn_result() - _populate_pbn_result(result, data, session) - return result - - def _is_crossref_data(raw_data): """Heurystyka: czy raw_data to JSON z CrossRef API.""" if not raw_data or not isinstance(raw_data, dict): @@ -912,7 +802,6 @@ def _verify_context(request, session, form=None): form = VerifyForm(initial=initial) existing = _find_duplicates(session) - pbn_result = _check_pbn_by_doi(session) doi = session.normalized_data.get("doi") suggest_crossref = bool(doi and session.provider_name != "CrossRef") @@ -945,7 +834,6 @@ def _verify_context(request, session, form=None): "auto_zwarte": (mapper.jest_wydawnictwem_zwartym if mapper else None), "suggest_crossref": suggest_crossref, "crossref_doi": doi if suggest_crossref else None, - "pbn_result": pbn_result, "field_categories": field_categories, "raw_json_pretty": raw_json_pretty, } @@ -1385,34 +1273,6 @@ def _create_streszczenia(session, record): ) -def _link_pbn_uid(session, record): - """Powiąż PBN UID z rekordem publikacji, jeśli znaleziono.""" - pbn_mongo_id = session.matched_data.get("pbn_mongo_id") - if not pbn_mongo_id: - return - - from django.db import IntegrityError - - from pbn_api.models import Publication - - try: - pbn_pub = Publication.objects.get( - mongoId=pbn_mongo_id, - ) - record.pbn_uid = pbn_pub - record.save(update_fields=["pbn_uid_id"]) - except Publication.DoesNotExist: - logger.info( - "Rekord PBN %s nie istnieje lokalnie — pominięto linkowanie", - pbn_mongo_id, - ) - except IntegrityError: - logger.warning( - "PBN UID %s jest już powiązany z innym rekordem BPP", - pbn_mongo_id, - ) - - @transaction.atomic def _create_publication(session): """Utwórz rekord publikacji na podstawie sesji.""" @@ -1456,14 +1316,10 @@ def _create_publication(session): _create_streszczenia(session, record) if session.zrodlo and normalized_data.get("year"): - from bpp.models.zrodlo import ( - uzupelnij_punktacje_z_zrodla, - ) + from bpp.models.zrodlo import uzupelnij_punktacje_z_zrodla uzupelnij_punktacje_z_zrodla(record, session.zrodlo, normalized_data["year"]) - _link_pbn_uid(session, record) - return record