Skip to content

feat(profil-autora): Faza 1 — konfigurowalne sekcje podstrony autora + pola profilu#385

Open
mpasternak wants to merge 43 commits into
devfrom
feature/profil-autora
Open

feat(profil-autora): Faza 1 — konfigurowalne sekcje podstrony autora + pola profilu#385
mpasternak wants to merge 43 commits into
devfrom
feature/profil-autora

Conversation

@mpasternak

Copy link
Copy Markdown
Member

Cel

Faza 1 funkcji „edytowalny profil autora + przebudowa podstrony autora”.
Pełna specyfikacja (z sesji brainstormingu) w repo:
docs/superpowers/specs/2026-06-18-profil-autora-i-podstrona-design.md.

Podstrona autora (/autor/<pk|slug>/) przestaje być „metadane + jeden
formularz wyszukiwania”, a staje się zestawem konfigurowalnych sekcji
(kolejność / widoczność / limit) renderowanych nad stałym nagłówkiem
tożsamości. Dane sekcji pochodzą z cache Rekord/Autorzy/AuthorConnection.

Co wchodzi w tej Fazie 1

Model

  • Autor: zdjecie (ImageField), biogram + biogram_format (md/html),
    uklad_profilu (JSONField), cached_property biogram_html.
  • Nowy WybranaPublikacjaAutora (GenericFK do polimorficznej publikacji).
  • Migracja 0444.

Logika (czysta, TDD)

  • bpp.util.biogram.renderuj_biogram: Markdown/HTML → bezpieczny HTML przez
    nowy safe_biogram_html (bogatszy zestaw tagów niż wąski globalny
    safe_html; usuwa treść script/style; linki rel="nofollow noopener").
  • bpp.util.obrazy.przetworz_zdjecie_autora: EXIF → center-crop → WebP 400×400.
  • bpp.profil_autora: rejestr 15 typów sekcji + walidacja i rozwiązywanie
    układu (wymuszona wyszukiwarka, forward-compat dla nowych sekcji).
  • bpp.profil_autora_dane: buildery danych każdej sekcji + auto-ukrywanie
    pustych.

Render

  • AutorView: render sekcji wg uklad_profilu (lub domyślnego, wariant
    „biogram-najpierw”; domyślnie ON także wykres publikacji w latach i
    współautorzy) + linki do raportu autora (bieżący rok / ostatnie 4 lata /
    szczegółowy formularz) pokazywane tylko gdy
    DefinicjaRaportu(slug="raport-autorow").widoczny_dla(request).
  • browse/autor.html przebudowany: stały nagłówek (z awatarem) + pętla sekcji;
    formularz wyszukiwania wydzielony do autor_sekcje/wyszukiwarka.html;
    partiale wszystkich sekcji; sekcja „kod do osadzenia” bez zmian.
  • Sekcja współautorów: lista z AuthorConnection + CTA do istniejącego
    wizualnego browsera sieci 2D/3D (bez nowej wizualizacji).
  • SCSS sekcji w _autor-bem.scss.

Admin

  • Fieldset „Profil na podstronie autora” (zdjęcie / biogram / format / układ),
    przetwarzanie i walidacja zdjęcia (≤5 MB → WebP) w AutorForm.clean_zdjecie,
    inline wybranych publikacji.

Testy

39 nowych testów w src/bpp/tests/test_profil/ (TDD: czyste jednostki —
biogram, zdjęcie, układ; modele; integracja widoku — render biogramu/
wyszukiwarki, ukrywanie sekcji, linki raportu public/inactive). Cała suita
test_profil + istniejące test_autor_autorzy zielone (43) na świeżym
kontenerze — bez regresji. manage.py check czysty, pre-commit (ruff/djLint/
TruffleHog) czysty.

⚠️ Do zrobienia przy scalaniu

make baseline-update (migracja 0444 zmienia schemat) — commit
baseline-sql/baseline.sql + baseline.meta.json. Świadomie nie robione w
branchu, żeby nie produkować konfliktów na wielkim pliku.

Świadomie poza zakresem (Faza 2, osobny PR)

Self-service edytor w „Mój profil” (drag-drop kolejności, przełączniki,
limity, upload zdjęcia z podglądem, live-preview biogramu, picker wyróżnionych
prac), eksport zbiorczy BibTeX/RIS. W Fazie 1 sekcja „eksport” oraz wypełnianie
zdjęcia/biogramu/układu działają przez Django admin.

🤖 Generated with Claude Code

mpasternak and others added 13 commits June 18, 2026 21:40
… autora

Projekt z sesji brainstormingu: konfigurowalne sekcje podstrony autora
(kolejnosc/widocznosc/limit), nowe pola Autor (zdjecie WebP 400x400,
biogram + biogram_format md/html), model WybranaPublikacjaAutora, rejestr
sekcji w kodzie + uklad_profilu JSON, render z auto-ukrywaniem pustych,
linki do raportu wg widoczny_dla, wspolautorzy z AuthorConnection + CTA do
browsera 2D/3D. Dostawa fazowa: Faza 1 (model+render+admin), Faza 2
(self-service edytor + RIS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rejestr sekcji

Czyste jednostki (TDD, 27 testów):
- bpp.util.biogram.renderuj_biogram: Markdown/HTML → bezpieczny HTML przez nowy
  safe_biogram_html (bogatszy zestaw tagów blokowych niż wąski globalny
  safe_html; usuwa treść script/style; linki dostają rel=nofollow noopener).
- bpp.util.obrazy.przetworz_zdjecie_autora: EXIF→crop kwadrat→WebP 400x400.
- bpp.profil_autora: katalog typów sekcji + walidacja i rozwiązywanie układu
  (kolejność/widoczność/limit, wymuszona wyszukiwarka, forward-compat).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…utora

Autor: zdjecie (ImageField), biogram + biogram_format (md/html),
uklad_profilu (JSONField) oraz cached_property biogram_html.
Nowy model WybranaPublikacjaAutora (GenericFK do polimorficznej publikacji).
Migracja 0444. Baseline odświeżyć przy scalaniu (make baseline-update).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + style

- profil_autora_dane: buildery danych każdej sekcji (listy prac, statystyki,
  wykres lat, dyscypliny, źródła, współautorzy z AuthorConnection) + auto-
  ukrywanie pustych sekcji.
- AutorView: render sekcji wg uklad_profilu (lub domyślnego) + linki do
  raportu autora (bieżący rok / 4 lata / formularz) gated DefinicjaRaportu
  .widoczny_dla.
- browse/autor.html: stały nagłówek (z awatarem) + pętla sekcji; formularz
  wyszukiwania wydzielony do sekcji autor_sekcje/wyszukiwarka.html; partiale
  wszystkich sekcji; embed-kod bez zmian.
- AutorAdmin: fieldset profilu (zdjęcie/biogram/format/układ), przetwarzanie
  zdjęcia w AutorForm.clean_zdjecie (≤5MB → WebP 400x400), inline wybranych
  publikacji.
- SCSS: style sekcji (awatar, listy, tabele statystyk, wykres słupkowy,
  współautorzy, linki raportu).

Testy: 4 integracyjne (render biogramu/wyszukiwarki, ukrywanie sekcji,
linki raportu public/inactive). Cała suita test_profil + istniejące
test_autor_autorzy zielone (43) na świeżym kontenerze — bez regresji.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Django-generated migracja miała linie >88 znaków; CI "Lint changed files"
uruchamia ruff-format na zmienionym zakresie z --exit-non-zero-on-fix.
To nowy plik migracji (nie istniejący), więc formatowanie jest dozwolone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Import bpp.util.biogram należy do grupy first-party (po bpp.util), nie do
grupy third-party po tinymce. Poprawka nie trafiła do poprzedniego commita.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spisane decyzje z 2026-06-19: układ 2-kolumnowy (lewa=klasyka+wizytówka,
prawa=kafelki analityczne), układ globalny per-Uczelnia (multi-uczelnia,
get_for_request), edytor kafelkowy admin-only, autor edytuje tylko
biogram+zdjęcie, klik w całą pozycję pracy, line-clamp opisów, wykres
liniowy >10 lat, klik w charakter → wyszukiwarka, historia zatrudnienia,
wykresy PK/IF. Dokument samowystarczalny dla wznowienia po resecie sesji.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ablon 2-kolumnowy

Rewizja 2-kolumnowa (§3.1–§3.3 handoffa):

- Układ profilu jest teraz GLOBALNY per-Uczelnia (multi-uczelnia):
  nowe pole Uczelnia.uklad_profilu_autora (JSONField). Usunięto
  Autor.uklad_profilu (override per-autor zbędny). Migracja 0445
  (AddField Uczelnia + RemoveField Autor; 0444 nietknięta).
- rozwiaz_uklad(uczelnia), przygotuj_sekcje(autor, uczelnia, request).
- Rejestr KATALOG_SEKCJI obejmuje tylko PRAWĄ kolumnę: usunięto
  biogram/wyszukiwarka/eksport oraz pole TypSekcji.obowiazkowa.
  Dodano klucze wykres_pk_lata + wykres_if_lata (buildery w §3.5).
- Szablon browse/autor.html przebudowany na Foundation grid w HTML
  (cell large-4 lewa: zdjęcie→biogram→jednostka→[historia §3.7]→
  identyfikatory→metryki→stopnie→opis→cytowania→wyszukiwarka→raport;
  cell large-8 prawa: pętla sekcji). Biogram i wyszukiwarka są stałe
  w lewej kolumnie (nie konfigurowalne).
- Admin: usunięto uklad_profilu z AutorForm/fieldsetu (edytor układu
  na Uczelni dochodzi osobnym commitem).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- _lista_prac.html: usunięto link [szczegóły]; każda pozycja <li> niesie
  data-href = praca.get_absolute_url, role="link", tabindex=0; opis w
  kontenerze .autor-page__praca-opis (line-clamp dochodzi w SCSS).
- autor.html: delegowany handler kliku/Enter nawiguje do data-href,
  pomijając kliknięcia w wewnętrzne <a> (DOI itp.) — bez zagnieżdżania
  <a> w <a>.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Wspólny partial _wykres_lata.html: >10 punktów → liniowy SVG
  (polyline + punkty z tooltipami, oś Y odwrócona transformem żeby
  liczyć współrzędne widthratio bez odejmowania), do 10 → słupki.
- _agreguj_po_latach(pary) — czysta agregacja (rok, wartosc) → suma/rok
  + maks + suma; pomija None.
- Buildery _wykres_pk_lata (suma punkty_kbn/rok) i _wykres_if_lata
  (suma impact_factor/rok; None gdy suma IF == 0 → auto-hide). _wykres_lata
  zyskuje etykietę. DISTINCT z id neutralizuje duplikaty joinu autorzy.
- Sekcje wykres_lata/wykres_pk_lata/wykres_if_lata delegują do partiala.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (§3.6)

- statystyki_charakter.html: każdy wiersz to POST do bpp:browse_build_search
  z autor=<pk> + charakter_formalny=<nazwa> (+ suggested-title). Nazwa, nie
  pk — CharakterFormalnyQueryObject.value_from_web rozwiązuje po `nazwa`
  (z potomkami MPTT).
- BuildSearch.post: dodano charakter_box przez CharakterFormalnyQueryObject,
  wpięty w oba warianty zrob_formularz (z/bez wydziałów). Zmiana addytywna —
  aktywna tylko gdy POST zawiera charakter_formalny.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Autor.historia_zatrudnienia() → Autor_Jednostka filtrowane po autorze,
  select_related(jednostka, funkcja), order_by(-rozpoczal_prace).
- _historia_zatrudnienia.html: lista „Jednostka — od–do (funkcja)";
  „obecnie" gdy brak zakonczyl_prace, „?" gdy brak rozpoczal_prace.
  Pusta historia → sekcja się nie renderuje.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
….1 admin + SCSS)

- UczelniaAdmin: nowy fieldset „Profil autora (podstrona)" z polem
  uklad_profilu_autora (JSON w textarea + opis). MVP edytora globalnego
  układu prawej kolumny.
- SCSS (_autor-bem.scss): klikalna pozycja listy prac (hover/focus) +
  line-clamp opisu (~3 linie); wykres liniowy SVG (linia/punkty/oś X);
  statystyki jako link-przycisk; historia zatrudnienia; drobne style
  kolumn (bez nadpisywania klas grid Foundation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/bpp/templates/browse/autor.html Fixed
Comment thread src/bpp/templates/browse/autor.html Fixed
…direction)

CodeQL zgłosił 2 high-severity alerty dla zapisu wartości z DOM
(data-href) do window.location. data-href pochodzi z get_absolute_url
(zaufane), ale dla pewności i zadowolenia skanera nawigujemy WYŁĄCZNIE
do ścieżek względnych w obrębie serwisu: walidacja /^\/[^/]/ odcina
javascript:, //host i http(s)://. Wspólny helper nawigujDoPracy().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/bpp/templates/browse/autor.html Fixed
mpasternak and others added 14 commits June 19, 2026 12:21
…odeQL)

CodeQL js/xss-through-dom flagował zapis wartości z DOM do
window.location (możliwy javascript:). Eliminujemy sink całkowicie:
zamiast data-href + JS używamy pustej nakładki <a> (position:absolute)
pokrywającej całą pozycję; wewnętrzne linki opisu (DOI) wynosimy ponad
nakładkę przez z-index. Prawdziwy, dostępny <a>, zero JS, brak
zagnieżdżenia <a> w <a>.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…za 2)

Zalogowany autor (user.autor) edytuje WŁASNY biogram (MD/HTML + podgląd
na żywo) i zdjęcie w „Mój profil":

- ProfilEdycjaView (UpdateView na request.user.autor) + AutorProfilForm
  (zdjecie/biogram/biogram_format), reużycie clean_zdjecie +
  przetworz_zdjecie_autora. WymagajAutoraMixin: anonim → login, zalogowany
  bez autora → przekierowanie na „Mój profil" z komunikatem.
- ProfilBiogramPodgladView — AJAX podgląd przez renderuj_biogram (ten sam
  pipeline sanityzacji co przy zapisie; XSS wycięty).
- URL-e bpp:profil-edycja, bpp:profil-biogram-podglad. Szablon z live
  preview (debounce, CSRF). Link „Edytuj swoją stronę" na „Mój profil".
- Układ NIE jest edytowalny przez autora (globalny per-Uczelnia).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lnosci)

test_publication_fulltext_search_uses_weighted_cached_fields wołał
dodaj_autora() (wymaga Typ_Odpowiedzialnosci "aut."), ale nie deklarował
tej zależności — polegał na danych bazowych, które poprzedzający test
transakcyjny mógł wyczyścić (flush). Dodanie testów w §3.8 zmieniło
podział pytest-split na shardy i ujawniło tę latentną kruchość (shard 0).
Dodajemy fixture typy_odpowiedzialnosci, która deterministycznie tworzy
pełny zestaw typów (w tym "aut.").

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Samowystarczalny handoff: stan brancha (CI zielone, PR #385), architektura,
lekcje (CodeQL stretched-link, §3.6 charakter po nazwie, pytest-split shardy),
świadomie odłożone (baseline-update + merge), oraz kandydaci na dalej
(weryfikacja wizualna, edytor kafelkowy układu, eksport BibTeX/RIS, picker
wyróżnionych prac).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… kalibracja)

Wykresy roczne (Publikacje/Punkty MNiSW/Impact Factor w latach) nie miały
żadnego odniesienia na osi Y — wartości czytelne tylko po najechaniu. Dodaje
lekką oś Y bez zależności (czysty SVG/HTML/CSS) dla obu wariantów:

- liniowy (>10 lat): kolumna HTML `wykres-osY` (maks u góry, 0 u dołu) obok
  SVG; dwie linie siatki jako `<line>` w grupie transformowanej (y=200 maks,
  y=100 połowa) z `vector-effect: non-scaling-stroke` — bez dystorsji.
- słupkowy (≤10 lat): etykieta maks (HTML) + górna linia siatki na poziomie
  najwyższego słupka.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dwa publiczne endpointy zwracające plik do pobrania ze wszystkimi
publikacjami autora:

- GET /bpp/autor/<pk>/eksport.bib  → BibTeX (reuse bpp.export.bibtex)
- GET /bpp/autor/<pk>/eksport.ris  → RIS (nowy moduł bpp.export.ris,
  zbudowany na wzór bibtex.py: per-typ konwertery + dispatcher)

Plus dwa przyciski "Eksport publikacji" (Foundation, fi-download) w lewej
kolumnie strony autora.

Limit MAKS_EKSPORT=5000 chroni przed OOM przy autorach z ogromną liczbą
prac; przy obcięciu BibTeX dostaje komentarz "% Wyeksportowano pierwsze
N z M", RIS (format liniowy) polega na samym limicie.

Testy TDD: src/bpp/tests/test_profil/test_eksport.py (6 testów, HTTP +
unit + edge: pusty autor / 404).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… dev)

CI testuje branch scalony z dev. Dev dodał 0444_alter_uczelnia_wyszukiwanie
(gałąź dev), profil dodał 0444_autor_biogram → 0445_remove_autor_uklad_profilu
(gałąź feature) — wspólny rodzic 0443 → dwa liście grafu migracji. 0446 to
pusta migracja scalająca (operations=[]) zależna od obu liści.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Zalogowany autor zarządza listą WŁASNYCH wyróżnionych publikacji na swojej
podstronie: dodaje (autouzupełnianie po własnym dorobku), usuwa i zmienia
kolejność. Persystencja do istniejącego modelu WybranaPublikacjaAutora
(bez nowej migracji).

Bezpieczeństwo egzekwowane serwerowo na każdej akcji:
- WymagajAutoraMixin gatuje dostęp (anonim->login, brak user.autor->profil),
- dodanie waliduje przynależność Rekordu do Rekord.objects.prace_autora(autor),
- usunięcie/przesunięcie filtruje wiersze przez autor=request.user.autor,
- duplikat (unique_together) to przyjazny no-op, nie 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… polish)

Opis bibliograficzny zawiera HTML (<b>/<i>); na liście i w podpowiedziach
JS wstawia tekst przez textContent (bezpiecznie, bez DOM-XSS), więc surowe
tagi były widoczne dosłownie. striptags (szablon) + strip_tags (autocomplete)
dają spójny, czytelny tekst.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(§3.2)

Zastępuje surowy textarea JSON dla Uczelnia.uklad_profilu_autora
przyjaznym, kafelkowym edytorem drag-drop w adminie uczelni:

- EdytorUkladuWidget (src/bpp/admin/widgets/uklad_profilu.py): renderuje
  kafelek dla KAŻDEJ sekcji katalogu (zapisana kolejność + doklejone
  brakujące z domyślem, forward-compat jak rozwiaz_uklad), z checkboxem
  widoczności, selectem limitu tylko dla sekcji ma_limit i ukrytym
  inputem z kanonicznym JSON-em.
- Szablon admin/widgets/uklad_profilu.html (emoji, single-line {# #}).
- JS uklad_profilu_edytor.js: jquery-ui .sortable() (z Grappelli) +
  re-serializacja kafelków do ukrytego inputa na drag/checkbox/limit,
  na django.jQuery, bez błędów konsoli.
- UczelniaAdminForm z clean_uklad_profilu_autora() sanityzującym przez
  waliduj_uklad(); podpięty jako form na UczelniaAdmin; opis fieldsetu
  zaktualizowany (drag-drop zamiast "wpisz JSON").

Serializacja zgodna ze schematem {"klucz","widoczna","limit"}
(walidowanym przez waliduj_uklad). 11 testów (TDD), wszystkie zielone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ji 0446)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ia, węższe wykresy

Feedback ze strony autora:
- kolumny large-4/large-8 -> large-6/large-6 (równy podział 50/50);
- zdjęcie większe (220px) i klikalne -> powiększenie w modalu Reveal
  (fallback bez JS: <a href> otwiera pełny obraz);
- historia zatrudnienia: bez sztucznej Obcej jednostki i bez wierszy bez
  daty rozpoczęcia (koniec z pytajnikami); filtr w modelu + przez AutorView;
- wykresy roczne domyślnie ostatnie 10 lat (OKNO_LAT_WYKRESU) i węższy blok
  (max-width) - czytelniejsze niż pełna, rozlana historia.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Klik w charakter na stronie autora budował poprawne zapytanie, ale pole
VALUE_LIST w multiseeku było puste: zapisywana goła nazwa nie równała się
żadnej opcji selecta (te są etykietami MPTT z prefiksem/spacją). Dodaje
CharakterFormalnyQueryObject.value_to_web mapujący nazwę na dokładną etykietę
listy - pole pokazuje wartość, zapytanie bez zmian.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mpasternak and others added 9 commits June 20, 2026 11:50
…rator/redaktor)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ct2)

Wyszukiwarka „dodaj publikację" w pickerze wyróżnionych prac używała własnego
widgetu (input + ręczna lista podpowiedzi), odstając wizualnie od reszty
serwisu, gdzie standardem jest Select2 (django-autocomplete-light). Rekord ma
złożony klucz (TupleField), więc zamiast ModelSelect2 używamy ListSelect2
(dowolne pary id/tekst) — tak jak globalna nawigacja. Endpoint zwraca teraz
format DAL/Select2 (results[].text + pagination). Media (jQuery+select2)
ładuje globalnie pasek nawigacji, więc nie dołączamy ich ponownie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…onie autora

Drobny feedback wizualny:
- modal powiększenia zdjęcia: klik otwiera TYLKO modal (preventDefault na
  linku), bez nawigacji do pełnego obrazu w nowym oknie; samo zdjęcie bez
  białego marginesu/tła Foundation Reveal, zaokrąglone rogi (selektor
  dwuklasowy .reveal.<modal> bije bazowe .reveal niezależnie od kolejności
  importów);
- statystyki wg charakteru: linki wyglądają jak zwykłe linki serwisu (kolor
  motywu $anchor-color, podkreślenie na hover, bez „kwadratowej ramki"
  / outline / box-shadow);
- wyszukiwarka „Opracowane w latach": checkbox i rok ZAWSZE w jednej linii
  (flex + nowrap), 3 lata w wierszu zamiast 6 (large-4) — czytelniej
  w węższej (50/50) lewej kolumnie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Link „Raport szczegółowy…" ze strony autora prowadził do pustego formularza —
pole wyboru obiektu (Select2) nie miało wybranego autora. Teraz link przekazuje
?obiekt=<pk>, a RaportFormView.get_initial czyta ten parametr i ustawia initial,
dzięki czemu DAL renderuje wybraną opcję (nazwisko autora). Działa też dla
poziomu jednostki/wydziału (ten sam mechanizm). Zły/nieistniejący pk nie wywala
formularza.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

Eksport publikacji autora budowany dotychczas synchronicznie w requeście
(N+1 przy materializacji [r.original ...]) przeniesiony do zadania Celery
ze stroną postępu (HTMX) i pobraniem-gdy-gotowe.

- Model AutorEksportTask (UUID pk, public) w src/bpp/models/eksport_autora.py
- @shared_task generuj_eksport_autora + cleanup usun_stare_eksporty_autora
  w src/bpp/tasks.py; parytet bajt-w-bajt z widokiem synchronicznym
- Widoki Start/Status/Download (publiczne, anonimowe; autoryzacja przez
  UUID + status), URL-e bpp:autor_eksport_{start,status,pobierz}
- Szablony task_status.html + _progress.html (HTMX poll co 2s, Foundation,
  auto-download); przyciski na stronie autora przepięte na flow async
- Stare synchroniczne URL-e/widoki zachowane (back-compat)
- Beat-schedule cleanup co 24h; migracja 0447

Mitigacja nadużyć anonimowych: dedupe (reuse zadania autor+format w oknie
5 min) + twardy limit MAKS_EKSPORT=5000.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…isie

Wyszukiwarka „dodaj wyróżnioną pracę" filtrowała tylko po tytule. Teraz pyta
po pełnym opisie bibliograficznym (opis_bibliograficzny_cache), więc znajduje
własne prace także po nazwisku WSPÓŁAUTORA, źródle czy roku — jak globalna
wyszukiwarka. Każde słowo musi wystąpić (AND), więc „Nowak 2020" zawęża
sensownie. Nadal wyłącznie w obrębie własnych prac autora (bezpieczeństwo).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Zdjęcie + biogram w jednej wizytówce; zdjęcie pływa w lewo, biogram opływa je
z prawej i od dołu (overflow:hidden domyka float). Wcześniej zdjęcie było
osobnym blokiem i zostawiało dużo pustego miejsca po prawej w szerszej (50/50)
lewej kolumnie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Każdy dawniej-sztywny blok lewej kolumny podstrony autora dostaje własny
partial w browse/autor_sekcje/ (zdjecie, biogram, jednostka, historia,
dyscypliny_naukowe, identyfikatory, metryki, stopnie, poprzednie_nazwiska,
opis, cytowania, raport, eksport). Markup przeniesiony 1:1 z autor.html
(zachowane bramki {% if %} i zamykające HR). historia_zatrudnienia.html
reużywa istniejący _historia_zatrudnienia.html.

Pliki na razie nieużywane (czysto addytywny krok) — wpięcie w układ
2-kolumnowy w kolejnym commicie. Bez zmiany zachowania, suita zielona.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Każdy element podstrony autora (lewa i prawa kolumna) jest teraz pozycją
rejestru otagowaną kolumną (lewa/prawa) z kolejnością, widocznością i
limitem — edytowalną per-Uczelnia. Domyślny układ odwzorowuje dzisiejszą
stronę (te same bloki lewej, te same sekcje prawej, 50/50).

Rejestr (profil_autora.py):
- TypSekcji.kolumna (+ template_only); schemat pozycji
  {klucz, kolumna, widoczna, limit}.
- KATALOG_SEKCJI obejmuje wszystkie bloki lewej kolumny + dotychczasowe
  prawe. Blok tożsamości „Dyscypliny naukowe" jako dyscypliny_naukowe
  (różny od statystycznej sekcji dyscypliny).
- waliduj_uklad uzupełnia brakującą kolumnę z katalogu (back-compat dla
  starych zapisów bez kolumny → prawa).
- rozwiaz_uklad zwraca dict {lewa, prawa}; sekcje spoza configu doklejane
  w swojej domyślnej kolumnie.

Dane (profil_autora_dane.py): przygotuj_sekcje zwraca obie kolumny;
sekcje template-only zawsze dołączane (partial sam się bramkuje),
data-driven pomijane gdy builder zwróci None.

Szablon (autor.html): obie kolumny renderowane z configu; szerokość lewej
z Uczelnia.szerokosc_lewej_kolumny (prawa = 12 - lewa). Float zdjęcia
domyka kolumna (flow-root) + clear na sekcjach (SCSS) — biogram opływa
zdjęcie jak dziś.

Model: Uczelnia.szerokosc_lewej_kolumny (4/6/8, default 6), migracja 0448.

Admin: dwustrefowy edytor kafelkowy (lewa ⇄ prawa, jquery-ui sortable
connectWith), serializacja z kolumną; pole szerokości w fieldset
„Profil autora (podstrona)".

Testy: test_uklad / test_edytor_ukladu / test_widok zaktualizowane do
nowego kontraktu (dict, kolumna, dwie strefy, szerokość, przeniesienie
biogramu do prawej); nowy test_przygotuj_sekcje. Cała suita test_profil
zielona (126 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mpasternak and others added 2 commits July 6, 2026 07:57
# Conflicts:
#	docs/redaktor/autorzy.md
#	src/bpp/admin/uczelnia.py
#	src/bpp/models/autor.py
#	src/bpp/templates/browse/autor.html
#	src/bpp/tests/test_fulltext_search.py
#	src/bpp/views/browse.py
#	src/nowe_raporty/tests/test_generyczne_widoki.py
Po scaleniu z dev renderowanie podstrony autora BEZ skonfigurowanej uczelni
(pusta baza / testy bez fixture'u) wywalało 500: base.html rozwiązuje
`uczelnia.skrot` twardo w breadcrumbie, a context-processor wstrzykuje w takim
przypadku sentinel `NiezdefiniowanaUczelnia` (ma `.skrot="NdU"`). AutorView
jednak przekazywał jawnie `uczelnia=None`, przesłaniając sentinel None-em.

Teraz klucz `uczelnia` trafia do kontekstu tylko gdy uczelnia istnieje; przy
None sentinel z context-processora zostaje nienaruszony. Logika Python-owa
(szer_lewej, link_do_pbn, przygotuj_sekcje, historia_zatrudnienia) dalej
dostaje realne None i jest na nie odporna (getattr / metody tolerują None).

Naprawia 8 testów test_profil/test_widok.py, które renderują podstronę bez
fixture'u `uczelnia`; jednocześnie usuwa latentny 500 w produkcji.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mpasternak added a commit that referenced this pull request Jul 7, 2026
Rozdział: dziedziczenie wydawcy po wydawnictwie nadrzędnym + podświetlenie wymaganego pola (Freshdesk #385)
mpasternak and others added 3 commits July 7, 2026 21:31
Sekcja na podstronie autora pobierająca na żywo (client-side) dane z
RAD-on scientist/search dla autorów z ORCID: stopnie/tytuły/wykształcenie/
zatrudnienie/dyscypliny. Dopasowanie po nazwisku + weryfikacja po ORCID
(scientist zwraca personalData.orcid). CORS otwarty. Ludzie Nauki i
projekty/publikacje świadomie poza zakresem (CORS zamknięty / brak filtra
po osobie).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…POL-on

Odkryte usługi POL-on filtrowalne po osobie (wszystkie CORS otwarty,
client-side): polon/projects (po kierowniku, weryfikacja projectManagers[].ORCID),
polon/products (patenty, po wynalazcy, inventors[].persons[].relatedOrcid),
polon/artisticAchievements (po autorze, authors[].orcid, + nagrody).
Publikacje świadomie pominięte (są w bazie BPP).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nowa sekcja template-only 'Osiągnięcia (RAD-on)' na podstronie autora,
widoczna dla autorów z ORCID. Dane pobierane na żywo w przeglądarce z
RAD-on OpenData przez @iplweb/radon-opendata (bundlowany esbuildem),
dopasowane po ORCID: stopnie/tytuły, projekty (z kwotami), patenty,
osiągnięcia artystyczne. Publikacje pominięte (są w bazie BPP).

- profil_autora: KLUCZ_RADON + wpis w KATALOG_SEKCJI (lewa kolumna)
- partial radon_osiagniecia.html: kontener [data-radon-osiagniecia],
  bramka po autor.orcid, podpis 'informacje pobrane z RAD-on'
- radon-profil.js: render przez textContent (anty-XSS), degradacja
  per-kontener bez wyjątku; wpięty w bundle-entry.js
- testy: 3 pytest (katalog + render kontenera) + 5 vitest (render/wire)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(profil-autora): sekcja osiągnięć z RAD-on OpenData (client-side, po ORCID)
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.

2 participants