Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Thumbs.db
htmlcov/
.tox/
.pytest_cache/
.ruff_cache/
.mypy_cache/
.hypothesis/
nosetests.xml
Expand All @@ -63,6 +64,7 @@ AUTHORS
CONTRIBUTORS
TODO


# Build artifacts
build/
dist/
Expand Down
15,570 changes: 7,780 additions & 7,790 deletions .test_durations

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions docker/bpp_base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ COPY pyproject.toml uv.lock yarn.lock package.json ./
# realnie potrzebne extras produkcji (ldap, office365).
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache \
uv sync --frozen --no-dev --no-install-project \
--extra ldap --extra office365
--no-editable --extra ldap --extra office365

# R6: pygad deklaruje matplotlib jako twardą dep dla funkcji rysowania
# zbieżności algorytmu genetycznego (plot_fitness), których BPP nie używa.
Expand Down Expand Up @@ -240,7 +240,7 @@ WORKDIR /build
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache \
uv sync --frozen --all-extras \
--all-groups --no-install-project
--all-groups --no-install-project --no-editable

# Przegladarki Playwright raz, do /opt/playwright (kopiowane do slim nizej).
RUN PLAYWRIGHT_BROWSERS_PATH=/opt/playwright \
Expand Down Expand Up @@ -461,7 +461,8 @@ ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache \
uv sync --frozen --all-extras --all-groups --no-install-project
uv sync --frozen --all-extras --all-groups \
--no-install-project --no-editable

# Yarn + grunt + collectstatic — mirror production builder, zeby:
# 1. /app/staticroot.baked istnial → entrypoint-appserver.sh przy starcie wybiera
Expand Down
2 changes: 2 additions & 0 deletions docs/deweloper/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ repozytorium. Poniższe strony rozwijają wybrane tematy:
(generowane maszynowo).
- [Polecenia](polecenia.md) — referencja komend (testy, build, Celery,
zarządzanie).
- [Pakiety klienckie PBN](pakiety-pbn.md) — pakiety `pbn-client` /
`django-pbn-client` (PyPI), podział odpowiedzialności i aktualizacja wersji.
- [Budowanie CSS/SCSS](budowanie-css.md) — pipeline frontendu (Grunt,
Foundation).
- [Rozwijanie projektu](rozwijanie-projektu.md) — jak współtworzyć.
Expand Down
58 changes: 58 additions & 0 deletions docs/deweloper/pakiety-pbn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Pakiety klienckie PBN

Kod integracji z PBN jest wydzielony do **dwóch samodzielnych pakietów**
publikowanych na PyPI (repozytoria pod `github.com/iplweb/`):

| Dystrybucja (PyPI) | Import Pythona | Repozytorium | Odpowiedzialność |
| --- | --- | --- | --- |
| `pbn-client` | `pbn_client` | [iplweb/pbn-client](https://github.com/iplweb/pbn-client) | HTTP, uwierzytelnianie i protokół API PBN (niezależne od Django) |
| `django-pbn-client` | `django_pbn_client` | [iplweb/django-pbn-client](https://github.com/iplweb/django-pbn-client) | abstrakcyjne modele Django i pobieranie/zapis stron PBN |

BPP zależy od obu dystrybucji jak od każdej innej zależności z PyPI
(`pyproject.toml`, sekcja `[project.dependencies]`). `django-pbn-client`
zależy dodatkowo od `pbn-client`. Istniejąca aplikacja `pbn_api`, jej etykieta
Django, konkretne modele i migracje pozostają w BPP. Moduł `pbn_api.models.base`
oraz część `pbn_api.exceptions`/`pbn_api.const` to cienkie warstwy zgodności
re-eksportujące klasy z nowych pakietów.

**W repozytorium BPP nie ma już katalogu `packages/` ani konfiguracji
`uv workspace`.** Zmiana kodu klienta = PR do właściwego repozytorium pakietu →
nowe wydanie na PyPI (przez GitHub Release + Trusted Publishing) → bump wersji
zależności w BPP.

## Podział odpowiedzialności

`pbn-client` jest warstwą protokołu i nie może zależeć od modeli BPP ani od
`pbn_api`. `django-pbn-client` udostępnia abstrakcyjne klasy bazowe oraz
generyczne usługi pobierania stron i zapisu (m.in. `download_to_model`,
`get_or_download`). **Nie** dostarcza konkretnych modeli lustrzanych — te,
ich relacje do BPP oraz historia migracji pozostają w `pbn_api`. Orkiestracja
importu, dopasowywanie rekordów, Celery i interfejs pobierania również
pozostają po stronie BPP.

Późniejsze wydzielenie konkretnych modeli wymagałoby zaprojektowania
konfigurowalnych relacji i osobnej strategii migracji; nie należy przenosić
istniejących migracji ani zmieniać etykiety aplikacji.

Pobieranie równoległe domyślnie używa wątków. Opcjonalny tryb
`method="processes"` korzysta z POSIX-owego `fork`, więc nie jest dostępny na
Windows.

## Aktualizacja wersji pakietu w BPP

```bash
# po wydaniu nowej wersji pakietu na PyPI:
uv add "pbn-client>=0.2,<0.3" # lub edycja pyproject.toml
uv sync --refresh-package pbn-client # --refresh gdy index uv jest zcache'owany
uv run python src/manage.py check
uv run python src/manage.py makemigrations --check --dry-run # brak dryfu pbn
```

## Wydawanie nowej wersji pakietu

W repozytorium danego pakietu (nie w BPP):

1. Bump `version` w `pyproject.toml`, merge do `main`.
2. Utwórz GitHub Release z tagiem `vX.Y.Z` — workflow `release.yml` publikuje na
PyPI przez **Trusted Publishing** (OIDC, bez tokena).
3. Zbump zależność w BPP (sekcja wyżej).
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ nav:
- deweloper/index.md
- Mapa kodu: deweloper/mapa-kodu.md
- Polecenia: deweloper/polecenia.md
- Pakiety klienckie PBN: deweloper/pakiety-pbn.md
- Import z SQLite (harvestery): deweloper/import-sqlite.md
- Budowanie CSS/SCSS: deweloper/budowanie-css.md
- Rozwijanie projektu: deweloper/rozwijanie-projektu.md
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ classifiers = [
requires-python = ">=3.11,<3.15"
dependencies = [
"Django>=5.2.16,<5.3",
# Reużywalne pakiety PBN wydzielone na PyPI (github.com/iplweb/*).
"django-pbn-client>=0.2,<0.3",
"pbn-client>=0.2,<0.3",
"django-polish-inflection>=0.1,<0.2",
"django-axes>=7.0,<9",
"arrow>=1.3,<2",
Expand Down
15 changes: 14 additions & 1 deletion src/bpp/models/uczelnia.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,11 @@ def pbn_client(self, pbn_user_token=None) -> "pbn_api.client.BppPBNClient":
Klient zna ``self`` jako swoją ``uczelnia`` — orchestracja czyta z niej
flagi zamiast zgadywać ``get_default()`` (kluczowe dla multi-hosted).
"""
from django.conf import settings
from pbn_client.conf import settings as pbn_defaults

from pbn_api import client
from pbn_api.reporting import rollbar_reporter

class UczelniaTransport(client.RequestsTransport):
def authorize(self, base_url, app_id, token):
Expand All @@ -839,7 +843,16 @@ def authorize(self, base_url, app_id, token):
raise ImproperlyConfigured("Brak tokena aplikacji dla API PBN")

transport = UczelniaTransport(
self.pbn_app_name, self.pbn_app_token, self.pbn_api_root, pbn_user_token
self.pbn_app_name,
self.pbn_app_token,
self.pbn_api_root,
pbn_user_token,
timeout=getattr(
settings,
"PBN_CLIENT_HTTP_TIMEOUT",
pbn_defaults.PBN_CLIENT_HTTP_TIMEOUT,
),
reporter=rollbar_reporter,
)
return client.BppPBNClient(transport, uczelnia=self)

Expand Down
3 changes: 3 additions & 0 deletions src/bpp/newsfragments/pbn-klienci-workspace.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Wydzielono komunikację z PBN i generyczny zapis danych Django do samodzielnych
pakietów ``pbn-client`` oraz ``django-pbn-client`` publikowanych na PyPI; BPP
zależy od nich jak od każdej innej zależności (bez katalogu ``packages/``).
15 changes: 15 additions & 0 deletions src/bpp/tests/test_models/test_uczelnia.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import pytest
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.test import override_settings
from django.urls import reverse
from model_bakery import baker

from bpp.models import Uczelnia
from pbn_api.reporting import rollbar_reporter


def test_Uczelnia_wydzialy(uczelnia):
Expand Down Expand Up @@ -77,6 +79,19 @@ def test_Uczelnia_pbn_client():
assert uczelnia.pbn_client()


@pytest.mark.django_db
@override_settings(PBN_CLIENT_HTTP_TIMEOUT="1,9")
def test_uczelnia_pbn_client_injects_bpp_transport_policy(uczelnia):
uczelnia.pbn_app_name = "app"
uczelnia.pbn_app_token = "token"
uczelnia.pbn_api_root = "https://pbn.example"

client = uczelnia.pbn_client("user-token")

assert client.transport.timeout == (1.0, 9.0)
assert client.transport.reporter is rollbar_reporter


@pytest.mark.django_db
def test_uczelnia_deklaracja_dostepnosci_tekst(uczelnia, client):
TEKST_Z_HTML = b"<h1>TEST</h1>"
Expand Down
10 changes: 10 additions & 0 deletions src/importer_publikacji/providers/pbn.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ def _get_pbn_client(uczelnia):
Wymaga JAWNEJ uczelni (multi-hosted) — bez zgadywania ``get_default()``.
Caller (provider/widok) ma uczelnię z requestu lub z ``ImportSession``.
"""
from django.conf import settings
from pbn_client.conf import settings as pbn_defaults

from pbn_api.client import PBNClient
from pbn_api.client.transport import RequestsTransport
from pbn_api.reporting import rollbar_reporter

if not uczelnia or not all(
[
Expand All @@ -54,6 +58,12 @@ def _get_pbn_client(uczelnia):
uczelnia.pbn_app_name,
uczelnia.pbn_app_token,
uczelnia.pbn_api_root,
timeout=getattr(
settings,
"PBN_CLIENT_HTTP_TIMEOUT",
pbn_defaults.PBN_CLIENT_HTTP_TIMEOUT,
),
reporter=rollbar_reporter,
)
return PBNClient(transport)

Expand Down
18 changes: 18 additions & 0 deletions src/importer_publikacji/tests/test_pbn_provider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from unittest.mock import MagicMock, patch

import pytest
from django.test import override_settings

from importer_publikacji.providers import (
get_available_providers,
Expand All @@ -17,15 +18,32 @@
_extract_license_url,
_extract_year,
_get_current_version_object,
_get_pbn_client,
)
from pbn_api.exceptions import (
AccessDeniedException,
HttpException,
PraceSerwisoweException,
)
from pbn_api.reporting import rollbar_reporter

SAMPLE_PBN_UID = "5e709189878c28a04737dc6f"


@override_settings(PBN_CLIENT_HTTP_TIMEOUT="3,7")
def test_get_pbn_client_injects_django_timeout_and_bpp_reporter():
uczelnia = MagicMock(
pbn_app_name="app",
pbn_app_token="token",
pbn_api_root="https://pbn.example",
)

client = _get_pbn_client(uczelnia)

assert client.transport.timeout == (3.0, 7.0)
assert client.transport.reporter is rollbar_reporter


SAMPLE_PBN_ARTICLE = {
"mongoId": SAMPLE_PBN_UID,
"status": "ACTIVE",
Expand Down
6 changes: 6 additions & 0 deletions src/pbn_api/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
SearchMixin,
)
from pbn_client.pagination import PageableResource
from pbn_client.reporting import default_reporter
from pbn_client.transport import PBNClientTransport, RequestsTransport
from pbn_client.utils import smart_content

Expand Down Expand Up @@ -91,5 +92,10 @@ class BppPBNClient(PBNClient, PublicationSyncMixin, DisciplinesMixin):
"""

def __init__(self, transport, uczelnia):
reporter = getattr(transport, "reporter", None)
if reporter is None or reporter is default_reporter:
from pbn_api.reporting import rollbar_reporter

transport.reporter = rollbar_reporter
super().__init__(transport)
self.uczelnia = uczelnia
Loading
Loading