Feature/multi hosted config#189
Open
mpasternak wants to merge 37 commits into
Open
Conversation
Add infrastructure for multi-hosted BPP configuration where one server can serve multiple universities on different domains. - Uczelnia: add OneToOne to django.contrib.sites.Site + theme_name field - BppUser: add M2M accessible_sites for per-user university access control - SiteResolutionMiddleware: resolves hostname → Site → Uczelnia on every request - Context processors: site-aware cache keys, per-uczelnia theme selection - Admin: site/theme fields in UczelniaAdmin, accessible_sites in BppUserAdmin - Data migration: links existing Uczelnia to Site(pk=1), grants staff access Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all per-uczelnia settings from django-constance to fields on the Uczelnia model, enabling per-university configuration in multi-hosted mode. - Add 8 new fields to Uczelnia: google_analytics_property_id, google_verification_code, pokazuj_oswiadczenie_ken, skrot_wydzialu_w_nazwie_jednostki, wydruk_margines_* (4 fields) - Context processor reads from Uczelnia instead of constance.config - Admin mixin reads scoring settings from Uczelnia instead of constance - Empty CONSTANCE_CONFIG (all settings migrated to Uczelnia) - Data migration copies existing Constance values to Uczelnia - UczelniaAdmin: add new fieldsets for Google, structure, margins Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add SiteFilteredAdminMixin to filter admin querysets by current uczelnia. Regular admins see only their university's data, superusers see all. - New SiteFilteredAdminMixin in src/bpp/admin/helpers/site_filtered.py - Applied to JednostkaAdmin (uczelnia), WydzialAdmin (uczelnia), AutorAdmin (aktualna_jednostka__uczelnia), UczelniaAdmin (pk filter) - FK dropdowns for wydzial/jednostka filtered per-uczelnia - Middleware blocks admin access for staff with accessible_sites configured but missing current site (backward compat: no sites = allow) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add uczelnia ForeignKey to PBN models that store per-institution data, enabling multi-tenant PBN operations. - Add uczelnia FK to: OsobaZInstytucji, PublikacjaInstytucji, PublikacjaInstytucji_V2, OswiadczenieInstytucji, SentData - Data migration links all existing records to first Uczelnia - Apply SiteFilteredAdminMixin to all 5 PBN admin classes - Fix PublikacjaInstytucji_V2.link_do_pi() to use self.uczelnia Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add site_cache_key utility and update admin filter count cache to include site_id, preventing cross-tenant cache pollution. - New src/bpp/cache_utils.py with site_cache_key() utility - Admin filter_count_view cache key includes site.pk - Fix test cache invalidation for per-site keys Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace Uczelnia.objects.get_default() with proper multi-site patterns: - Views: use get_for_request(request) or self.request - Celery tasks: add uczelnia_id parameter with fallback to get_default() - Management commands: add --uczelnia-id argument - Refactor pbn_integrator handle() to reduce complexity (C901 33→<10) - Fix UP031 percent format → f-strings in ranking_autorow - Refactor ranking get_queryset() to reduce complexity (C901 13→<10) 28 files updated across tasks, commands, views, admin helpers, and menu. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace Uczelnia.objects.get_default() in model/utility code that has no request context, by adding uczelnia parameter with fallback. bpp models: - jednostka.py: use self.uczelnia in get_default_ordering - abstract/pbn.py: add uczelnia param to link_do_pbn, _format_link_pi - abstract/disciplines.py: add uczelnia param to przelicz_punkty_dyscyplin - multiseek_registry/fields: add uczelnia param to option_enabled - admin/helpers/pbn_api/cli.py: add uczelnia param, fix B904 raise from PBN import/integrator utilities: - pbn_import/utils: add uczelnia param to all importer classes - pbn_integrator/utils: add uczelnia param to scientists and institutions - pbn_import/templatetags: use request from template context Other: - zglos_publikacje: forms accept uczelnia kwarg, model uses _uczelnia attr - importer_publikacji: add uczelnia param to helpers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SITE_ID configurable via DJANGO_BPP_SITE_ID env var (default=1) - Add DJANGO_BPP_ENABLE_SITEMAPS env var to disable static-sitemaps in multi-hosted mode (static-sitemaps generates for one domain only) - django_countdown already multi-site friendly (uses get_current_site) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New test fixtures (conftest_multisite.py): - site1/site2, uczelnia1/uczelnia2, staff users per-site - wydzial/jednostka/autor per-uczelnia - make_request_for_site() helper for simulating domain requests Middleware tests (test_site_resolution.py, 9 tests): - Hostname→Site→Uczelnia resolution - Fallback to SITE_ID for unknown hosts - Staff blocked from wrong site's admin (403) - Superuser allowed everywhere - Anonymous allowed on public pages - Backward compat: staff with no sites configured Admin filtering tests (test_site_filtered.py, 5 tests): - Jednostka/Wydzial filtered per-uczelnia for staff - UczelniaAdmin shows only own uczelnia for non-superuser - Superuser sees all data Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Article model: add M2M uczelnie field (default: all universities) - ArticleAdmin: filter_horizontal for uczelnie, auto-assign all on create - Browse view: filter articles, recently_updated, abstracts, total count by authors from current uczelnia's units - Root view: use get_for_request instead of .first() - Data migration: assign existing articles to all uczelnie - Fix get_absolute_url to use self.uczelnie.first() Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PBN_Export_Queue: add uczelnia FK + SiteFilteredAdminMixin in admin Data migration links existing records to first Uczelnia - Deduplikator autorów/publikacji: has_module_permission = superuser only (deduplikacja jest operacją globalną, nie per-uczelnia) - Rozbieżności IF/PK/dyscyplin: TODO markers for per-uczelnia filtering Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rozbieżności dyscyplin: - RozbieznosciViewAdmin/RozbieznosciZrodelViewAdmin: filter by autor__aktualna_jednostka__uczelnia for non-superusers Rozbieżności IF/PK: - RozbieznosciIfLogAdmin/RozbieznosciPkLogAdmin: filter by rekord__autorzy_set__jednostka__uczelnia with distinct() - IgnorujRozbieznoscIf/PkAdmin: superuser-only (GenericFK) Autocomplete: - AutorAutocompleteBase: filter by aktualna_jednostka__uczelnia when request._uczelnia is set (admin context) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 integration tests verifying multi-site data isolation: - Article visible only on assigned uczelnia - Article on both uczelnie when both assigned - Staff cannot see other uczelnia's jednostki in admin - Staff gets 403 on wrong uczelnia's admin - Browse record count scoped per uczelnia Fix: browse view queryset used invalid `original__autorzy_set` path (original is a cached_property, not a DB field). Changed to `autorzy__jednostka__in` which is the correct ORM path for Rekord materialized view. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per Ultraplan review: change BppUser M2M from Site to Uczelnia for clearer semantics — user has access to universities, not domains. - BppUser.accessible_sites (M2M→Site) → accessible_uczelnie (M2M→Uczelnia) - Migration: add new field, copy data (Site→Uczelnia via OneToOne), remove old - Middleware: check access by uczelnia instead of site - Admin: update fieldset reference - Fixtures + tests: updated to use accessible_uczelnie Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Łączy leafy grafu migracji powstałe po rebase feature/multi-hosted-config: - bpp: 0413_bppuser_autor_onetoone (dev) + 0415_rename_accessible_sites_to_uczelnie (feature) - miniblog: 0003_alter_article_article_body (dev) + 0004_assign_articles_to_all_uczelnie (feature)
Dwie pozostałości po Phase 4 — Uczelnia.objects.first() i .all().first() w widoku rankingu autorów. W multi-site zwracały losową uczelnię zamiast tej z bieżącego requestu, przez co podgląd "uzywaj_wydzialow" i "pokazuj_liczbe_cytowan_w_rankingu" nie respektował ustawień uczelni hostującej daną stronę.
Code: - autocomplete/authors.py: getattr(getattr(self, "request", None), ...) zamiast self.request — view'y są instancjonowane bezpośrednio w testach bez routingu HTTP. - browse.py:JednostkiView.get_paginate_by: użyj None-safe Uczelnia.objects.get_for_request, zamiast hasattr-ochrony zwracającej static fallback. Testy zaktualizowane do nowego API: - test_handlers.test_handler403_permission_denied: @pytest.mark.django_db (SiteResolutionMiddleware sięga do DB jak handler403/404/500). - pbn_export_queue test_admin: patch admin.ModelAdmin.response_change zamiast __bases__[1] (po dodaniu SiteFilteredAdminMixin baza ModelAdmin przesunęła się na index 2). - test_browse: a.uczelnie.set([uczelnia]) — Article jest M2M-przypisany do uczelni od Phase: Miniblog M2M. - test_oai, test_ewaluacja_no_queries: bump query budgetu o +3 (Site.get + site.uczelnia + cache lookup z SiteResolutionMiddleware). ImportError w django_pg_baseline/tests/test_rebuild.py jest pre-existing na dev (eb1a124), nie regresja tej gałęzi.
Bugfixy (request był dostępny, ale używano get_default()/first()): - bpp/context_processors/orcid.py — orcid_login_enabled flag. - orcid_integration/backends.py — auth backend's authenticate(request) ignorował request. Realny problem bezpieczeństwa: w multi-site uczelnia.orcid_tylko_dla_pracownikow rozstrzygane było po losowej uczelni, nie tej z hosta. - bpp/admin/jednostka.py — get_changeform_initial_data(self, request). - ranking_autorow: refactor RankingAutorowForm — sygnatura __init__(self, lata, *args, request=None, **kwargs), klasowa lambda w polu rozbij_na_jednostki przeniesiona do __init__. View przekazuje request przez get_form_kwargs. Site OneToOne obowiązkowe: - Model: usunięto null=True, blank=True z Uczelnia.site. - Migracja 0417_ensure_uczelnia_site_not_null: data migration fail-loudly dla niejednoznacznych przypadków, AlterField NOT NULL. - Setup wizard (UczelniaSetupForm.save) — auto-link do get_current_site(request). - Admin (UczelniaAdmin.save_model) — auto-link przy tworzeniu nowej Uczelni. - Test util any_uczelnia + fixture uczelnia w conftest_models — get_or_create Site(domain="testserver") jeśli nie podano. - test_views_browse: zamiana Uczelnia.objects.create(...) na any_uczelnia(...). Pełny suite: 3682 passed, 0 failed.
Zmiana semantyki przypisania artykułu do uczelni: - Niepusty M2M ``Article.uczelnie`` = artykuł widoczny tylko na wybranych uczelniach (bez zmian). - Pusty M2M = artykuł widoczny na WSZYSTKICH uczelniach (lazy resolution zamiast eager-assignment z ArticleAdmin.save_model). Zalety vs. poprzednia implementacja (admin save_model assign all): - Nowo utworzona Uczelnia automatycznie widzi artykuły z pustym M2M (przed zmianą trzeba było ręcznie edytować artykuły dodane przed nową uczelnią). - Edycja artykułu z czyszczeniem M2M = "pokazuj wszędzie" (przed: artykuł znikał wszędzie, bo save_model sprawdzał `not change`). Implementacja: - ``Article.objects.visible_on(uczelnia)`` manager method z ``Q(uczelnie=uczelnia) | Q(uczelnie__isnull=True)``. - ``bpp.views.browse.get_uczelnia_context_data`` używa ``visible_on`` zarówno dla listy ostatnich artykułów, jak i dla pojedynczego artykułu (``get_object_or_404``). - Usunięto ``ArticleAdmin.save_model`` (eager-assignment do wszystkich). Tests: - ``test_article_with_empty_m2m_visible_on_all_uczelnie`` — nowy test weryfikujący lazy resolution. - Istniejące testy isolation/explicit-assignment zostają zielone. Brak migracji — zgodnie z decyzją, brak istniejących instalacji do zaktualizowania.
Plik .docker-build juz nie istnieje (skasowany w poprzednim commicie), wiec elif sprawdzajacy `[ -f ".docker-build" ]` byl dormantnym kodem. Zastapione: push na non-master (czyli feature/fix/hotfix przez restrykcje triggera) → buduj zawsze. Realizuje user-intent "auto-build na feature branches" — bez tego push na feature spadalby na else (skip), a `.docker-build` flag nie istnieje. Komentarze i opisy aktualizowane — bez wzmianek o pliku flagi. Pozostale `docker-build` w workflow to label PR-a (mechanizm zostaje). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wycofuje gating labelem .docker-build/docker-build na rzecz prostszej zasady: master/main push i workflow_dispatch buduja zawsze (release flow + manual override), pozostale (PR sync, feature/fix/hotfix push bez PR) — tylko gdy actor=mpasternak. Inni contributorzy nie pala Docker Cloud minutek; jesli trzeba zbudowac obraz dla cudzego PR-a: `gh workflow run build-docker-images.yml --ref <branch>`. Dev branch dopisany jawnie do komentarza w pushu jako "intentionally excluded" — push do dev nie odpala buildu (intermediate state nie zasluguje na obraz, release leci przez master). Dodany main do triggerow obok master (gdyby kiedys repo zmienilo default branch — single source of truth). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Multi-hosted deployment (jedna instalacja BPP, wiele uczelni/domen)
nie mieścił się w pojedynczym DJANGO_BPP_HOSTNAME. Wprowadzona zmienna
DJANGO_BPP_HOSTNAMES (CSV) rozwiązuje to bez breaking change:
- Jeśli ustawisz DJANGO_BPP_HOSTNAMES, jest source-of-truth dla
ALLOWED_HOSTS i CSRF_TRUSTED_ORIGINS. Pierwszy element listy staje się
canonical hostname (settings.DJANGO_BPP_HOSTNAME) — wykorzystywany przez
Rollbar do identyfikacji deployment'u w raportach błędów.
- Jeśli HOSTNAMES jest puste, używamy single DJANGO_BPP_HOSTNAME jak
wcześniej. Existujące deployments nie wymagają zmian konfiguracji.
Zmienione pliki:
- settings/base.py: parsing CSV w DJANGO_BPP_HOSTNAMES, derive HOSTNAME
z pierwszego elementu listy.
- settings/local.py, production.py: ALLOWED_HOSTS rozszerzony o pełną
listę zamiast pojedynczego env('DJANGO_BPP_HOSTNAME').
- .env.docker, .env.example: udokumentowano obie zmienne i ich relację.
Tests: 3683 passed, 0 failed (full suite).
Walidacja konfiguracji (base.py): - DJANGO_BPP_HOSTNAME i DJANGO_BPP_HOSTNAMES ustawione naraz → ImproperlyConfigured (intencja niejasna). - DJANGO_BPP_HOSTNAME zawiera przecinek → ImproperlyConfigured (na multi-host używaj HOSTNAMES). - DJANGO_BPP_HOSTNAMES bez przecinka lub tylko jeden host po sparsowaniu → ImproperlyConfigured (na single-host używaj HOSTNAME). Custom Rollbar middleware (bpp/middleware.py): - Dotychczasowy DJANGO_BPP_HOSTNAME (canonical/installation identity) zostaje. - Dodatkowo per-request: request_host (vhost gdzie padło zgłoszenie) + uczelnia_skrot/uczelnia_pk z request._uczelnia (ustawiane przez SiteResolutionMiddleware). - DisallowedHost przy request.get_host() łapany ostrożnie i raportowany jako sentinel "<DisallowedHost>" — Rollbar handler nie powinien failować przy raportowaniu błędu, który sam jest DisallowedHost. Tests: 3683 passed, 0 failed.
Pięć miejsc używało Site.objects.first()/get_current() do budowy URL-i
w eksportach XLSX/BibTeX. W multi-hosted to losowy host — eksport
wygenerowany na uczelnia1 mógł zawierać linki na uczelnia2.
Wspólny helper bpp.util.site_url_for_request(request=None):
- z requestem: f"{scheme}://{host}".
- bez requestu (CLI/Celery): fallback do Uczelnia.objects.get_default()
.site, dalej Site.objects.first(), ostatecznie "https://localhost".
Naprawione miejsca:
- bpp/admin/xlsx_export/resources.py: Wydawnictwo_ResourceBase trzyma
request z kwargs (przekazane przez ImportExportModelAdmin).
- rozbieznosci_dyscyplin/admin.py: RozbieznosciViewResource +
RozbieznosciZrodelViewResource analogicznie.
- deduplikator_autorow/utils/export.py + views.py: export_duplicates_to_xlsx
bierze request opcjonalnie, propagacja z download_duplicates_xlsx.
- deduplikator_zrodel/utils.py + views.py: analogicznie.
- ewaluacja2021/util.py: output_table_to_xlsx (CLI/Celery context),
helper fallbackuje do default Uczelnia.site.
Drobne pre-existing fixy w ewaluacja2021/util.py (wymagane przez
ruff hook): rename `a`/`col`/`dirs` na `_`, # noqa: E402 dla
intencjonalnych mid-file imports, # noqa: C901 dla output_table_to_xlsx.
Plus IDE fix w bpp/admin/uczelnia.py:save_model: try/except
ImproperlyConfigured przy obj.pbn_client() (gdy admin ustawi
pbn_integracja=True ale nie wypełni pbn_app_name/token).
Tests: 3683 passed, 0 failed.
Dodaje przycisk „Importuj" w admin/bpp/jednostka/. Plik XLSX (kolumny:
Uczelnia, Wydział, Katedra/Zakład/Klinika) jest parsowany przez nowy
JednostkaImportResource:
- Uczelnie muszą istnieć (lookup po nazwa) — błąd per-wiersz w GUI.
- Brakujące Wydziały tworzone get_or_create przez WydzialGetOrCreateWidget
z auto-generowanym skrot (max 10) i skrot_nazwy (max 250).
- Puste komórki Wydział/Katedra dostają domyślne nazwy
(„Wydział <skrót uczelni>", „Jednostka Wydziału <X>").
- import_id_fields=("nazwa",) + skip_unchanged → idempotentny re-import.
- before_save_instance auto-generuje Jednostka.skrot i ustawia
aktualna=True na nowych wierszach.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wcześniej autocomplete twardo filtrował autorów po aktualna_jednostka.uczelnia == request._uczelnia, przez co nie dało się wybrać: - wieloetatowca z aktualną jednostką w innej uczelni federacji - byłego pracownika (brak aktualnej jednostki, ale Autor_Jednostka u nas) - autora bez żadnego przypisania (np. świeżo zaimportowanego z PBN) Zamiast filtrować, autocomplete annotuje każdy wynik etykietą grupy (Case/When + Exists na Autor_Jednostka) i sortuje po niej. Override get_results renderuje 3 optgroupy w odpowiedzi Select2 — JS po stronie klienta nie wymaga zmian (Select2 obsługuje optgroup natywnie): ✅ Autorzy z naszej uczelni 🏛️ Autorzy powiązani historycznie z naszą uczelnią 🌐 Autorzy zewnętrzni get_result_label zostaje bez zmian — emoji per-option (📚 PBN, 🏛️ MNISW, [❌ USUNIĘTY]) działa jak wcześniej. Naprawia 5 testów Playwright padających pre-merge na multi-hosted-config: test_podpowiedzi_dyscyplin_autor_ma_jedna_uczelnia_podpowiada (ciagle/zwarte) oraz test_procent_odpowiedzialnosci AutorFormset jeden_autor (ciagle/zwarte) i dobrze_potem_zle_dwoch_autorow (patent). Wszystkie 5 używały autorów bez aktualna_jednostka, których stary filtr odsiewał z autocomplete.
241 commits, ~530 plików. Multi-hosted nadrzędne nad zmianami dev. Konflikty rozstrzygnięte: - src/bpp/util.py (UD): dev rozbił monolit na pakiet bpp/util/. site_url_for_request() przeniesiona do bpp/util/bpp_specific.py. - src/bpp_setup_wizard/views.py (UD): dev przepisał setup wizard na django-first-run-wizard. Nadpisujemy on_complete() w UczelniaSetupStep żeby przekazać request do form.save(request=request). - src/bpp/admin/helpers/constance_field_mixin.py (UU): dev'owy bool() workaround dla constance bezprzedmiotowy (Phase 1 wycofało constance). - src/bpp/views/browse.py (UU): multi-host filtrowanie news przez siteblog.Article.sites M2M (Q(sites=site)|Q(sites__isnull=True)). recently_updated/recent_abstracts/total_rekord_count nadal per uczelnia. - src/miniblog/ (UU): apka to pusta wydmuszka dla historii migracji (cutover do siteblog na dev'ie). Nasze migracje 0003-0005 wywalone. - src/deduplikator_autorow/admin.py (UU): dev przemianował IgnoredAuthor → IgnoredScientist + dodał nowy IgnoredAuthor. has_module_permission (superuser-only) na obu Admin klasach. - src/przemapuj_prace_autora/test_integration.py (UU): cache.delete dla per-site kluczy (Phase 5) + invalidate_all() (cacheops query cache). - src/zglos_publikacje/forms.py (UU): łączenie z dev'owym wizard rewrite — uczelnia kwarg w nowej sygnaturze __init__. - src/zglos_publikacje/models.py (UU): clean() używa self._uczelnia z fallbackiem (Phase 6.2-6.4). - src/bpp/tests/test_multisite/test_isolation.py: 3 testy przepisane z miniblog.Article.uczelnie → siteblog.Article.sites. Migracja merge: - 0418_merge_20260521_1015.py: łączy 0416_rename_dynamic_columns_to_admin (dev) i 0417_ensure_uczelnia_site_not_null (multi-host). Pre-commit fix-ups (ręcznie, manual): - .github/workflows/docs.yml (z dev): persist-credentials: false (zizmor artipacked). - .pre-commit-config.yaml: mkdocs.yml do check-yaml exclude (pymdownx.slugs.slugify python tag); 3 templaty z dev (rozbieznosci_if, rozbieznosci_pk, snapshotodpiec_list) do djlint exclude (orphan-tag pattern w if/else). - src/django_bpp/asgi.py: # noqa: E402 na late imports po django_asgi_app = get_asgi_application(). - src/bpp/models/konferencja.py: # noqa: DJ001 na 4 CharField'ach z null=True (pre-existing tech-debt z dev'a, wymaga migracji w follow-up). - src/bpp/migrations/0416_rename_dynamic_columns_to_admin.py: usunięty nieużywany `from django.apps import apps as django_apps`. - src/fixtures/conftest_browser.py: usunięty nieużywany `from django.core.exceptions import ImproperlyConfigured`. - src/zglos_publikacje/tests/test_forms.py: usunięty nieużywany `from django.core.files.uploadedfile import SimpleUploadedFile`. - Whitespace fixes: HISTORY.md + 7 docs/*.md (pre-commit auto-fix). - Ruff import order: drobne reordering w 7 plikach (third-party przed first-party). Smoke: Django check OK, importy bpp.util.site_url_for_request, bpp.views.browse, zglos_publikacje.forms, bpp_setup_wizard.steps, siteblog.Article wszystkie działają. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ia.site NOT NULL) Po mergu origin/dev w branch feature/multi-hosted-config zostało 5 failures i 3 errors w testach. Tylko wzorce wymagające adaptacji do nowego stanu po mergu — same testy są poprawne, ale używały API z przed mergea. - src/bpp/tests/test_views/test_browse/test_browse.py: test_artykuly i test_artykul_ze_skrotem używały `a.uczelnie.set([uczelnia])` (M2M na starym miniblog.Article). Po mergu Article to siteblog.Article z M2M `sites` (do django.contrib.sites.Site). Zamiana na `a.sites.set([uczelnia.site])` — fixture uczelnia ma `.site` (OneToOne do Site, mandatory po 0417). - src/bpp/tests/test_views/test_views_browse.py: 3 testy używały `Uczelnia.objects.create(nazwa="X", skrot="X")` — to lata przed 0417 migracją wymuszającą Uczelnia.site NOT NULL. Zamiana na helper `any_uczelnia()` (już użyty wcześniej w tym pliku), który auto-tworzy Site i przypina go. - src/deduplikator_autorow/tests/test_xlsx_orcid_and_pbn_url.py: fixture `candidate_with_orcid_and_pbn` używała `Uczelnia.objects.get_or_create` bez `site=` w defaults. Dodane `site` (get_or_create na testserver). Wszystkie 468 testów w merge-targeted suite passuje (test_multisite, test_middleware, test_views, test_admin/test_site_filtered, bpp_setup_wizard, zglos_publikacje, deduplikator_autorow, miniblog, przemapuj_prace_autora). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ia.site NOT NULL) Demo data generator tworzył Uczelnię bez site, co po migracji 0417 (Uczelnia.site mandatory) wywalało NotNullViolation we wszystkich testach test_demo_data (28 testów: 7 failures + 21 errors w jednej fixturze jednostki_fixture która tworzy uczelnię przez ensure_uczelnia). W kontekście CLI/demo nie ma requestu więc get_current_site nie zadziała — bierzemy pierwszy Site (zwykle django.contrib.sites fixture 'example.com'), albo tworzymy 'demo.local' jeśli baza pusta. Tests: 74 passed (test_demo_data full suite + 2 flaky które przy okazji się przeszły). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…palety (#238) * feat: dodano trzy nowe zestawy kolorystyczne frontend dla uczelni Dodano trzy nowe frontend themes dla BPP, nawiązujące kolorystyką do stron uczelni: 1. Uniwersytet VIZJA (vizja.pl): - Szary (#3a3a3a) z żółtymi akcentami (#fbb800) - Tło: #f8f8f8 - Buttons: żółte z czarnym text - Links: żółte akcenty (#fbb800) 2. MWSLiT Wrocław (mwsl.eu): - Granat (#003688) z pomarańczowymi akcentami (#ff6b35) - Tło: #f5f8ff - Buttons: pomarańczowe z białym text - Links: granatowe z pomarańczem na hover 3. UFAM (ufam.edu.pl): - Niebieski (#0056b8, #003688) - Tło: #f5f8ff - Buttons: niebieskie z białym text - Links: niebieskie akcenty Nowe pliki: - src/bpp/static/scss/_settings_vizja.scss - ustawienia Foundation dla Vizja - src/bpp/static/scss/_settings_mwsl.scss - ustawienia Foundation dla MWSL - src/bpp/static/scss/_settings_ufam.scss - ustawienia Foundation dla UFAM - src/bpp/static/scss/app-vizja.scss - theme Vizja - src/bpp/static/scss/app-mwsl.scss - theme MWSL - src/bpp/static/scss/app-ufam.scss - theme UFAM Każdy theme importuje odpowiedni _settings_*.scss z kolorami, a resztę ustawień pobiera z domyślnego settings.scss. Aby użyć nowego theme, w settings/base.py zmień DJANGO_BPP_THEME_NAME na odpowiedni plik CSS (scss/app-vizja, scss/app-mwsl, scss/app-ufam). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: run_site buduje assets + nowe themes w COMPRESS_OFFLINE_CONTEXT 1. run_site automatycznie buduje frontend assets (make assets) - Nowa metoda _build_assets() wywołuje make assets na początku - Opcja --skip-assets dla devs którzy mają aktualny CSS - Graceful degradation: błędy assets są tylko warningi 2. Dodano nowe frontend themes do COMPRESS_OFFLINE_CONTEXT: - scss/app-vizja.css (Uniwersytet VIZJA - szary z żółtymi akcentami) - scss/app-mwsl.css (MWSLiT Wrocław - granat z pomarańczem) - scss/app-ufam.css (UFAM - niebieski) Nowe themes są dostępne dla django-compress do offline kompresji i cachowania. Aby użyć nowego theme, zmień DJANGO_BPP_THEME_NAME w settings na odpowiedni plik CSS (scss/app-vizja, scss/app-mwsl, scss/app-ufam). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: dodano nowe uniwersyteckie themes do Gruntfile.js Dodano trzy nowe frontend themes do konfiguracji Grunt: - vizja: scss/app-vizja.scss → scss/app-vizja.css - mwsl: scss/app-mwsl.scss → scss/app-mwsl.css - ufam: scss/app-ufam.scss → scss/app-ufam.css Te taski są teraz budowane równolegle z resztą themes przez grunt concurrent:themes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(university-themes): poprawki kolorów i ikon kalendarza - App-vizja: przyciemnienie złotego koloru z #fbb800 na #d4a000 dla lepszej czytelności na szarym tle #f8f8f8 - Ikona kalendarza: dodanie override dla .uczelnia__tile aby używała koloru z klasy .uczelnia__tile-icon zamiast $primary-color (kafe na głównej stronie mają teraz własne kolory) - Ptaszki dropdown: zmiana hardcoded koloru rgba(44, 62, 80, 0.6) na rgba($anchor-color, 0.6) dla spójności ze theme'ami Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(university-themes): MWSL i UFAM jako samodzielne theme'y Foundation Rozszerzono _settings_mwsl.scss i _settings_ufam.scss z minimalnej formy (@import 'settings') do pełnego, samodzielnego setu zmiennych Foundation. Każdy theme zawiera teraz wszystkie 56 sekcji konfiguracji Foundation z dostosowanymi kolorami uczelni — dzięki temu zmiany w bazowym _settings.scss nie wpływają na wygląd theme'ów uczelnianych. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(university-themes): palety zgodne z brandem + rename UFAM→UAFM - MWSL: primary #ff6b35→#e35b00, secondary #003688→#002b53 (1:1 z mwsl.eu) - VIZJA: primary #d4a000→#EFA402, secondary #3a3a3a→#01608C (federacjavizja.pl) - UAFM (poprzednio UFAM): primary #0056b8→#b41906, secondary #003688→#045595, alert #cc4b37→#df1a17 (uafm.edu.pl); zmiana nazwy plików, taska Grunta i THEME_NAME w base.py - Usunięto globalną regułę .fi-calendar { color: $primary-color; } z app-vizja, app-uafm, app-mwsl, app-green, app-orange — kolor kalendarza wyciekał na cały serwis; teraz kolor pochodzi wyłącznie z modyfikatora uczelnia__tile-icon--* na kafelku homepage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Migracja docsow z Sphinxa na MkDocs Material (87a76da) pozostawila kilka rozsianych odwolan do Sphinxa — sprzatamy je. - Makefile: live-docs -> mkdocs serve (zamiast sphinx-autobuild) - docs/SECURITY_PRACTICES.md: wyjatek dla live-docs opisany przez docs/requirements.txt (mkdocs-material) zamiast sphinx-autobuild - SECURITY.md + docs/SECURITY.md: HISTORY.rst -> HISTORY.md (plik HISTORY.md istnieje od dawna, RST byl martwym odsylaczem) - bin/scan-deps.sh: przyklad dev-only paczki w komentarzu sphinx -> mkdocs - AUTHORS.rst -> AUTHORS.md (jedyny pozostaly .rst w repo, niczego nie referowal, tresc juz w docs/authors.md ale plik w roocie zostawiamy dla widocznosci GitHuba) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ications
1. check-flag hint: na pull_request evencie github.ref_name to
"<PR>/merge" (np. 189/merge) ktorego workflow_dispatch nie akceptuje
("HTTP 422: No ref found for: 189/merge"). Dodane HEAD_REF z
github.head_ref (nazwa branchu zrodlowego PR-a) + fallback do
ref_name dla nie-PR eventow.
Przed: gh workflow run build-docker-images.yml --ref 189/merge (fail)
Po: gh workflow run build-docker-images.yml --ref feature/multi-hosted-config
2. docker/bpp_base/Dockerfile: usuniety martwy COPY z
src/notifications/static/notifications/js/. src/notifications/ apka
zostala usunieta na dev w commicie 048c2cf (notifications JS jest
teraz dostarczane przez pakiet django-channels-broadcast, ktory
wyladuje pliki z venv w runtime collectstatic). Powodowalo to fail
docker builda na "failed to compute cache key: ... /src/notifications/
static/notifications/js: not found".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.