0.2.54 (2026-03-09) ------------------- - Added canonical repository class names: ``PostQuerySnapshot``, ``PostDetailContext``, ``BlogIndexContext``, ``FeedContext``, and ``EpisodeFeedContext``. - Added canonical repository serialization APIs: ``serialize_audio``/``deserialize_audio``, ``serialize_video``/``deserialize_video``, ``serialize_image``/``deserialize_image``, ``serialize_blog``/``deserialize_blog``, ``serialize_post``/``deserialize_post``, ``serialize_episode``/``deserialize_episode``, and ``serialize_transcript``/``deserialize_transcript``. - **Breaking change:** removed legacy repository class aliases ``QuerysetData``, ``PostDetailRepository``, ``BlogIndexRepository``, ``FeedRepository``, and ``EpisodeFeedRepository``. - **Breaking change:** removed legacy serialization aliases ``audio_to_dict``, ``video_to_dict``, ``image_to_dict``, ``blog_to_dict``/``blog_from_data``, ``post_to_dict``, ``episode_to_dict``, and ``transcript_to_dict``. - Canonical names are now the only supported API surface for repository classes and serialization helpers. - Repository hardening pass: - removed dead `PostQuerySnapshot.create_from_post_queryset(..., is_podcast=...)` API surface and dead branch - fixed repository-layer import coupling (`HtmxHttpRequest`/`PostFilterset`) by moving to type-only/local imports - guarded `add_site_raw` SQL fallback for empty-site rows (`fetchone() is None`) - corrected media ID aliases to use `set[int]` - removed dead `CastBlock` type alias and `Site` package re-export - narrowed transcript exception handling to avoid masking `AttributeError` - added `EpisodeFeedContext` to model reference docs - removed duplicate URL computation in `data_for_blog_cachable` by serializing URL maps in `add_queryset_data` - fixed `FeedContext.create_from_django_models` to handle `Site.find_for_request(request) is None` - Secured media detail API authorization: - `VideoDetailView` and `AudioDetailView` now scope object lookup to `request.user`, preventing cross-user retrieve/delete. - Added regression tests for owner and non-owner GET/DELETE behavior, including unauthenticated DELETE responses. - Hardened styleguide helper account setup: - the styleguide user is now forced to `set_unusable_password()`, `is_active=False`, and removed from the `Moderators` group. - added regression tests to guarantee the styleguide account remains non-login and de-privileged. - Fixed request-state leakage in ``Post.get_context()`` by avoiding mutation of the page instance (``owner``/``page_url``); request-specific values are now applied to a context-local page object instead. - Fixed rich-text internal page-link cache isolation by replacing the process-global ``PageLinkHandlerWithCache.cache`` dict with context-local storage, preventing cross-request/thread cache leakage during concurrent rendering while preserving existing link-resolution behavior. - Hardened ``Audio.save()`` persistence flow by wrapping enrichment in a database transaction and collapsing up to three writes into one initial save plus at most one targeted follow-up update, reducing partial-update risk while preserving duration and file-size metadata behavior. - Fixed ``Video._create_poster()`` file-handle lifecycle by closing the ``mkstemp`` descriptor, context-managing poster file reads, and always cleaning up the temporary poster file; added regression tests for success, save-failure, and missing-temp-file cleanup paths. - Fixed stale settings reads in ``cast.appsettings`` and ``cast.renditions`` by resolving settings at runtime so ``@override_settings`` changes are respected after module import. - Aligned test ``INSTALLED_APPS`` with shipped ``CAST_APPS`` by reusing ``cast.apps.CAST_APPS``, ensuring ``rest_framework``, ``django_htmx``, and ``wagtail.api.v2`` are present in tests and adding regression checks to prevent future app-list drift. - Hardened ``media_replace`` with safe defaults: it now requires explicit ``--yes`` confirmation for destructive writes, supports non-destructive previews via ``--dry-run``, and reports per-file operations plus summary counts for planned/replaced/skipped/errors. - Added new Django system checks for configuration safety: ``cast.E002`` validates ``cast.comments.apps.CastCommentsConfig`` is listed before ``django_comments`` in ``INSTALLED_APPS``, and ``cast.E003`` validates all middleware listed in ``cast.apps.CAST_MIDDLEWARE`` are present in ``settings.MIDDLEWARE``. - Hardened ``select_theme`` POST redirects by validating ``next`` with ``url_has_allowed_host_and_scheme`` against the current host/scheme and falling back to the local select-theme URL when ``next`` is empty or unsafe. - Fixed runtime comment setting lookups so ``cast.comments`` form/helper CSS and exclude-field settings are resolved lazily instead of freezing at import time. - Fixed the comments fallback ``CRISPY_TEMPLATE_PACK`` default to ``bootstrap4`` so AJAX validation errors still render when projects rely on django-cast's built-in crispy setup without redefining that setting. - Pinned the CI ``uv`` installation step to ``0.10.2`` for more predictable workflow behavior. - Fixed Python 3.11-3.13 compatibility for ``Post`` model imports by replacing a runtime-evaluated ``"Blog" | None`` annotation with ``Optional["Blog"]``. - Typed Django system check callables in ``cast.checks`` so ``uv run mypy`` no longer emits ``annotation-unchecked`` notes during the release gate. - Fixed migration ``0063_gallery_signature`` for current Django versions by providing an explicit ``chunk_size`` when iterating a prefetched queryset. - Hardened ``recalc_video_posters`` with progress output, per-video error handling, and completion summaries so one broken video no longer aborts the entire command. - Replaced mutable class-level fallback repository dicts in ``blocks.py`` with per-instance mappings. - Reduced settings drift by making ``tests.settings`` import shared defaults from ``cast.settings`` and keep only explicit test-specific overrides. - Hardened ``media_stale`` so cleanup now preserves live ``Audio`` and ``Transcript`` assets instead of misclassifying them as stale. - Made the optional theme-template contract more forgiving by falling back to ``cast/plain`` when a discovered theme omits ``transcript.html`` or ``gallery_modal.html``. - Added ``just test-slow`` so contributors can run only the intentionally slower integration/dev-surface tests that complement ``just test-fast``. - Restricted ``GET /api/comment_training_data/`` to staff users so comment training exports are no longer exposed to arbitrary authenticated users. - Made slug-based feed, transcript, and meta endpoints site-scoped so multisite installs resolve pages within the current site tree instead of failing on duplicate slugs. These lookups now intentionally stay limited to live pages. - Hardened ``sync_renditions --blog-slug`` to raise ``CommandError`` when a slug is missing or ambiguous instead of silently targeting the wrong blog. - Fixed ``Video.save()`` follow-up poster persistence so ``force_insert`` and ``objects.create()`` paths no longer trigger a duplicate insert. - Hardened the gallery modal view to return a controlled 404 when the requested image was deleted after the page HTML was rendered. Migration mapping (old -> new): ========================= ========================== Removed Replacement ========================= ========================== ``QuerysetData`` ``PostQuerySnapshot`` ``PostDetailRepository`` ``PostDetailContext`` ``BlogIndexRepository`` ``BlogIndexContext`` ``FeedRepository`` ``FeedContext`` ``EpisodeFeedRepository`` ``EpisodeFeedContext`` ``audio_to_dict`` ``serialize_audio`` ``video_to_dict`` ``serialize_video`` ``image_to_dict`` ``serialize_image`` ``blog_to_dict`` ``serialize_blog`` ``blog_from_data`` ``deserialize_blog`` ``post_to_dict`` ``serialize_post`` ``episode_to_dict`` ``serialize_episode`` ``transcript_to_dict`` ``serialize_transcript`` ========================= ==========================