Skip to content

[Draft] Patch release v06.08.2026 - #6081

Draft
marcellamaki wants to merge 37 commits into
masterfrom
hotfixes
Draft

[Draft] Patch release v06.08.2026#6081
marcellamaki wants to merge 37 commits into
masterfrom
hotfixes

Conversation

@marcellamaki

@marcellamaki marcellamaki commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

Studio patch release

References

Reviewer guidance

PR Issues Category QA Focus QA status
#6050 #5993 Enhancement See detailed description below

The email workflow is a new feature we added to support Laura (on our team, who is doing most of the administrative duties for the Community Library). We noticed that people were not making edits to their channels/not seeing the in-Studio notifications, so we are adding an automated email workflow.

  1. Sign in as a "regular" studio user, and submit to community library -- note, use an email that you will have access to, for confirmation email testing
  2. Sign in as a studio admin, and review the submission
  3. Accept the submission
  4. Ensure a confirmation email is sent to the submitter's email address. NOTE - it will not be translated yet.
  5. Repeat this process for a "needs changes" community library request. In this case, the "notes" from the reviewer of what needs to be changed should be included in the body of the email.

PR Issues Category QA Focus QA status
#5960 N/A refactor (1) Type in in the text editor, click out of the text box focus to elsewhere on the page and ensure the "preview" (read-only mode) is accurate. (2) Type text into an editor, then immediately close the editor/modal or click "Save" without first clicking outside the text box. Confirm your text (or other addition - like image) saved. ✔️
#5969 #5954 performance Confirm the admin user CSV export completes without timing out and returns the same data as before, testing a large user set ✔️
#5996 #5994 UX improvement As admin, open a Community Library submission (e.g. via a notification's "view more") — confirm the Review button, Actions dropdown, and side panel appear. Then repeat as a non-admin and confirm they still see the read-only view only ✔️
#5986 #5973, #5974 Migrations / Backend N/A
#5995 #5975 Performance Improvement regression only: confirm file upload still works ✔️
#6036 N/A Backend N/A
#6037 N/A File storage N/A
#6040 #6004 Publishing N/A
#6041 #5987 Bug Publish a channel containing a file >2.1GB, then confirm the exported size is correct instead of wrong/missing
#6061 #5907 UX improvement Submit a community library channel with multiple resources, and each license having at least two resources with that license. Then look at the Licenses field for a Community Library channel (via the channel details modal, a submission's details panel, or the admin review side panel) and confirm no license name appears more than once in that list ✔️
#6076 N/A UX improvement In the admin Channels table, filter by "Community Library" + "Needs review", open a channel, then hit Back — confirm filters persist; confirm the status button no longer clips long labels ✔️

AI usage

I used claude code to set up the markdown table quickly and do a draft of QA focus, then went through and cross-checked and edited the guidance (because some of it was terrible)

AlexVelezLl and others added 30 commits June 4, 2026 12:29
…value

Previously the editor emitted an `update` on every editor state change via a
deep watcher on `editor.state`. This caused frequent re-serialization and
required an `isUpdatingFromOutside` flag to break the feedback loop when
applying parent-driven content updates.

Now the markdown update is emitted only when the editor loses focus (blur),
and the latest emitted markdown is cached. When `prop.value` changes, it is
compared against the cache so an echoed-back value skips unnecessary
re-rendering of the editor content.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
refactor(TipTapEditor): emit markdown on blur and cache last emitted value
Optimize query for user CSV export
Gate SubmissionDetailsModal review actions on isAdmin from the Vuex
store rather than an adminReview prop, so admin users arriving via any
route automatically see the Review button and side panel.

Remove the adminReview prop and all call sites that set it; simplify
administration/router.js to props: true.
Route admins from notification "view more" into submission review mode
…inting

- CI linting of new migrations on pull requests
- Declarative dual-write trigger decorator (mirror_field)
- Reusable batched-backfill command (idempotent, resumable, throttled)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LfZvkigk8hdsKdEif3hzBi
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LfZvkigk8hdsKdEif3hzBi
Expand stage of the zero-downtime int->bigint widening:
- Add nullable file_size_bigint shadow column and its index (built CONCURRENTLY).
- Mirror file_size into it via the change-guarded @mirror_field trigger.
- Wire the online backfill as a commented deploy-migrate step.
- Stage the cutover and contract steps as comments on the File model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LfZvkigk8hdsKdEif3hzBi
Almost zero-downtime migration tooling; widen File.file_size to bigint (expand stage)
- supports_resumable flag on the GCS storage backends
- get_stored_object_md5: dedup lookup against an object's GCS-computed md5
- create_resumable_upload_session: pins md5 + declared-size metadata
- hex_to_base64 checksum helper

Part of #5975.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzUP3UYP4cLyouvssXyekj
- accept a `resumable` flag (defaults off)
- GCS: skip when the stored md5 matches the checksum, else return a server-initiated resumable session URI
- non-GCS backends fall back to single-PUT
- reject non-resumable uploads over 500 MB
- make `size` an IntegerField, dropping the redundant float casts

Part of #5975.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzUP3UYP4cLyouvssXyekj
Add opt-in resumable uploads to the file upload URL endpoint
…ar import

The GCS storage backend imports utils.files at module load. files' top-level
`from contentcuration.models import File / generate_object_storage_name` then
re-entered a partially initialized contentcuration.models during app boot
(DEFAULT_FILE_STORAGE=GCS), raising ImportError and crash-looping the pods.
The test suite missed it: pytest imports models early, so models is complete
before the storage modules load files.

Move File and generate_object_storage_name imports into their call sites
(create_file_from_contents, get_file_diff, get_thumbnail_encoding).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ineqU2EGLAcWW2WPWR3mE
…import

Fix circular import breaking deploy
…objects

The resumable upload_url path calls get_stored_object_md5(filepath) to dedup
against a stored object's md5. On CompositeGCS this delegated to
_get_readable_backend(name), which raises FileNotFoundError when the object is
in no backend -- i.e. every not-yet-uploaded file -- 500ing upload_url for all
new resumable uploads. Catch FileNotFoundError and return None, matching
GoogleCloudStorage.get_stored_object_md5 for a missing blob.

Add regression tests for the found and not-found cases; the not-found test
fails against the pre-fix code (FileNotFoundError).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ineqU2EGLAcWW2WPWR3mE
Provides RENDERABLE_PRESETS_ORDER for the included_presets bitmask.
The new le-utils adds a QTI question type to exercises.question_choices,
which Django picks up as an assessmentitem.type AlterField migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a nullable included_presets IntegerField to the abstract
kolibri_content.base_models.File, inherited by both the kolibri_content
(sqlite export) and kolibri_public (import-metadata API) File mirrors.
It holds a bitmask of the renderable presets a device needs to render a
file. The column is additive and nullable, so old Kolibri ignores it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In create_associated_file_objects, set each renderable (non-supplementary)
file's own-preset bit (2 ** RENDERABLE_PRESETS_ORDER.index(preset_id)) and
leave supplementary files NULL. A preset missing from the append-only
ordering is logged and skipped rather than aborting the channel publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add VERSION_6 carrying included_presets and set it as CONTENT_SCHEMA_VERSION
so new Kolibri knows an export carries the column. MIN_CONTENT_SCHEMA_VERSION
stays VERSION_5 since the column is additive and returned regardless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: export included_presets renderable bitmask for content-schema import gating
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: export 64-bit file_size_bigint at publish
AlexVelezLl and others added 6 commits August 3, 2026 07:40
Some ChannelVersion rows were backfilled with duplicate license IDs by
a past one-off migration command, causing repeated license chips/names
to show in the community library submission and review UIs. Dedupe
defensively in the two viewset read paths that serve this field,
rather than backfilling the affected rows.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…table

Navigating back to the admin Channels table (e.g. after opening a
channel and using the browser back button) reset the status filter
even though it was correctly restored from the URL. An immediate
watcher unconditionally overwrote it to the first available option on
every mount instead of only defaulting when the filter is actually
unset. Since the status filter is derived from the current channel
type's options, a status no longer valid for a new type already reads
back as unset, so a single "is it set" check covers both the
type-change reset and back-navigation preservation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The fixed width clipped longer status labels. Let it size to content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d-licenses-dedup

Dedupe ChannelVersion.included_licenses in API responses
@pcenov

pcenov commented Aug 5, 2026

Copy link
Copy Markdown
Member

@marcellamaki regarding Publish a channel containing a file >2.1GB, then confirm the exported size is correct instead of wrong/missing - seems that this can't be tested manually because we have a file upload limit of 210 MB per file. Let me know if there's a workaround for this one.

Add ability to send a notification email on review of community libra…
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.

6 participants