Releases: kobotoolbox/kpi
2.026.07h
What's changed
Bug Fixes (1)
- subsequences: allow accepting nlp actions even if limit exceeded (#6927)
Ensure users can save/delete automatic NLP results even if they are over
their usage limits.
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07g..2.026.07h
2.026.07g
What's changed
Performance (1)
- beat: throttle Beat schedule reloads to fix dispatch starvation (#6926)
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07f..2.026.07g
2.026.07f
What's changed
Bug Fixes (1)
- massEmails: do not disable emails before they are sent (#6915)
Fixes a bug that was disabling one-time email sends before they could be
sent.When users created one-off emails after the daily send lists had been
generated, they were automatically getting turned off (havingLiveset
to False) before they could actually be sent.
Full Changelog: 2.026.07e...2.026.07f
2.026.07e
What's changed
Performance (1)
- longRunningMigrations: optimize 0020 batch strategy (#6913)
Internal migration improvement — no user-visible change.
Testing (1)
- hooks: fix SSRF IP mock in hook log tests (#6890)
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07d..2.026.07e
2.026.07d
What's changed
Bug Fixes (4)
-
longRunningMigrations: make 0020 batch size small to avoid OOM (#6875)
-
map: OpenStreetMap 403r error (#6869)
Adds missing piece of configuration to fix 403r Access blocked error
when rendering OpenStreetMap map.👷 Description for instance maintainers
The new global default Referrer-Policy response header (introduced for
OpenStreetMap tiles) can be overridden per environment via the
SECURE_REFERRER_POLICY. -
userReport: fix
mfa_is_activenot reflecting correct MFA status in user-reports (#6861)Fixes an issue where the
/api/v2/user-reportsAPI was not correctly
reflecting MFA status for users who had MFA enabled.Users who recently enabled MFA were still showing
mfa_is_active: false
in the/api/v2/user-reportsAPI response and within their underlying
UserProfilerecord. -
userReports: prevent infinite loop in MV background job (#6876, #6878)
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07c..2.026.07d
2.026.07c
What's changed
Bug Fixes (1)
- longRunningMigrations: retry on transient DB errors, fix 0011 extra_details (#6858)
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07b..2.026.07c
2.026.07b
What's changed
Features (1)
- accounts: extend activation link window to 24 hours and update related email/UI copy (#6832)
Extends the django-allauth email confirmation expiration to 24 hours and
updates the corresponding email templates, UI pages, and unit tests to
reflect the new timeframe and provide better user guidance.This PR extends the validity of all activation links to exactly 24 hours
and updates the associated UI and email copy to be more user-friendly
and clear.
Bug Fixes (1)
- pairedData: empty field intersection exposes no data (#6848)e
When a connected project's dynamic data field restrictions did not
overlap between source and destination, the external XML file was not
generated correctly.
Performance (2)
-
asset: store version content hash in DB to avoid loading its content (#6843)
Opening a project with many deployed versions and many questions could
return a 502 error.👷 Description for instance maintainers
In the API response of the asset detail endpoint
(/api/v2/assets/{asset_uid}/), the hash of the content of each version
was computed on the fly, loading all their JSON into memory (could be
many MB, even GB of objects in memory at once).A new database field now stores the hash directly on each version
record, computed once when the version is saved. A long-running
migration backfills the hash for all existing records in small batches
to avoid memory spikes. -
openrosa: reduce SQL queries on formList and manifest endpoints (#6844)
Continous Integration (1)
- zulip: update channel name as per zulip channel renames (#6851)
Full Changelog: https://github.com/kobotoolbox/kpi/compare/2.026.07a..2.026.07b
2.026.07a
What's changed
Bug Fixes (3)
-
admin: prevent manual username changes for existing users in Django admin (#6839)
This PR locks down the
usernamefield in the Django admin panel for
existing users, preventing superusers from manually changing it and
breaking the_userform_idmapping in MongoDB.Manually changing a username via the Django admin updates the relational
database but leaves MongoDB documents out of sync. Because the
_userform_idkey in MongoDB relies on the original username, altering
it breaks submission retrieval and detaches submissions from their
correct projects. -
permissions: org admins can see and manage all asset permissions (#6836)
Organization admins were unable to see other users' permission
assignments on projects belonging to their organization.Organization admins receive
manage_assetimplicitly through their org
role — noObjectPermissionrecord is created in the database. The
permission visibility logic for both the asset detail endpoint and the
organization assets list relied solely on explicit DB records to
determine whether the requesting user could see all assignments. As a
result, org admins were silently treated as regular users and could only
see the owner's and their own permissions, making it impossible to
manage sharing from the project detail page. -
scripts: display detailed error output on unexpected migration failures (#6830)
Fixes a logging issue in
scripts/migrate.shwhere unexpected migration
tracebacks were hidden from the console, restoring standard error
visibility for developers.In a recent update (see
kpi#6796), we automated
the resolution of materialized view schema locks during deployments. To
achieve this, we updatedscripts/migrate.shto capture the output of
the Djangomigratecommand into a bash variable ($MIGRATE_OUT) so we
could scan it for specific locking errors.However, this had an unintended side effect: it swallowed the Python
traceback for all other types of migration crashes. If a migration
failed for an unrelated reason (like a broken model or bad arguments),
the developer only saw a generic "failed for an unknown reason" message,
making debugging incredibly difficult.This PR fixes that oversight by ensuring the
$MIGRATE_OUTvariable is
explicitly echoed to the console before the script exits, restoring full
Django error visibility when unexpected migration failures occur.
Full Changelog: 2.026.07...2.026.07a
2.026.07
What's changed
Features (24)
-
massEmails: exclude trashed users from email lists (#6615)
Ensure users who cannot log in do not receive emails.
Filter out any user who is already in the trash bin or who has been
explicitly set to not active (as distinguished from users who we
determine to be inactive by a lack of activity). -
massEmails: exclude users who have submitted from inactive emails (#6618)
Exclude users who have recently made submissions to any project from
receiving inactive user emails.Previously we only counted users as active if they submitted to their
own projects, but not projects owned by others. -
processing: handle new subsequences API on frontend (#6657)
-
processing: handle non-blocking UI for NLP answers (#6671)
Allow users to enter QA answers very fast while they are saved in
background. -
processing: handle "in_progress" status (#6677)
-
processing: toast on saving transcripts and translations (#6681)
-
processing: handle failure errors (#6678)
-
qa: rename qual to manual_qual (#6555)
Rename the "qual" action to "manual_qual."
-
qual: show most recently created qual answers instead of most recently accepted (#6575)
Display the most recent QA answers in the data table and exports rather
than the most recently accepted. -
qual: add new automatic QA action (#6567)
Update advanced features API to allow requesting LLM answers to QA
questions.Add a new "automated_chained_qual" action to the advanced features API
endpoints. It is currently only a stub and will return canned answers
rather than actually hitting an LLM. -
submissions: support
rootUuidas{id}parameter for data detail endpoints (#6660)Allow data detail endpoints to be accessed using rootUuid as the primary
identifier.Description
This feature adds support for using
rootUuidas the `{id} parameter
when accessing data detail endpoints. This makes it possible to retrieve
a submission directly by its root UUID. The change improves flexibility
and consistency when working with submission identifiers, without
altering existing behavior for clients that continue to use the original
primary key format. -
subsequences: add model and new endpoints for advanced actions (#6492)
-
subsequences: show supplemental columns in data table (#6523)
Add supplemental NLP columns to data table.
This is just for adding the columns to the data table. They may not be
populated correctly. If an NLP action is enabled, there will be a column
for it, even if there are presently no responses. -
subsequences: stop using _advanced_features field (#6503)
-
subsequences: implement
get_output_fieldsandtransform_data_for_outputforQualAction(#6504)Add implementation of
get_output_fields()and
transform_data_for_output()inQualAction.This update enables qualitative analysis results to appear correctly in
exports or the table view.
The new logic:- Defines the output fields for each qualitative question (including
labels, types, and choices). - Converts stored qualitative results into export-ready values,
including expanding choice UUIDs into readable label objects.
- Defines the output fields for each qualitative question (including
-
subsequences: migrate old advanced_features (#6545)
-
subsequences: migrate old SubmissionExtras to SubmissionSupplemental (#6422)
-
subsequences: allow hiding of QA questions (#6550)
-
subsequences: add OpenAPI schema for advanded features (#6547)
Add OpenAPI schema for the
/api/v2/assets/{uid_asset}/advanced-features/endpoint.The API schema output files and the generated Orval types have been
updated with the schema details for the action parameters in the
QuestionAdvancedFeaturemodel. -
subsequences: show again in formpack exports (#6561)
-
subsequences: do not allow users to un-accept automatic NLP responses (#6628)
Do not allow users to un-accept an automatic NLP response.
-
subsequences: add
localefield to NLP actions documentation (#6620)Updated the API documentation to explicitly include the
locale
parameter for NLP actions. -
subsequences: do not allow translation of deleted transcripts (#6649)
This PR implements a new validation rule within the subsequence
processing flow. It ensures that a translation action cannot proceed if
its source transcription (Manual or Automatic) has been explicitly
deleted, regardless of whether a previously accepted version exists in
the history. -
viewer: improve user-agent parsing for Enketo and Collect (#6780)
The user-agent string displayed in submission metadata is now more
human-readable for ODK Collect, Kobo Collect, and Enketo submissions.Previously, submissions from ODK Collect, Kobo Collect, or Enketo would
show a generic browser/OS string instead of a meaningful identifier.
This change adds dedicated parsing logic.
Bug Fixes (72)
-
ci: pin pip<25.3 to restore compatibility with pip-tools 7.x (#6435)
Fixes a CI installation issue caused by an incompatibility between
pip25.3 andpip-tools7.x. -
datacollectors: remove links on group delete (#6650)
-
dev: fix formpack version in dependencies files (#6616)
Ran pip-compile script to update the formpack version to the latest
commit -
drawer: icon size (#6654)
-
formbuilder: update tooltips under some formbuilder buttons (#6582)
Formbuilder header buttons had some incorrect tooltip, this PR updates
them to at least be relevant to the button they're associated with -
frontend: ensure useOrganizationAssumed assumption holds (#6608)
Don't sometimes crash the website at the data table route.
-
hub: [breaking] fix hub merge conflict (#6687)
Fixes a migration conflict in the hub app
-
languages: unauthorize languages endpoint (#6699)
Allow anonymous users to access the languages endpoint
-
logging: prevent duplicate logs by disabling propagation to root logger (#6808)
Celery workers were emitting every log record twice, polluting logs and
making debugging harder.When a logger is configured with
propagate: True(the default), log
records are passed up the logger hierarchy all the way to the root
logger. Because Django's logging setup attaches a handler both on the
named logger and on the root logger, each record was processed twice —
once by the named handler and once by the root handler — resulting in
every log line appearing duplicated.Setting
propagate: Falseonconsole_loggerstops records from
bubbling up, so each log record is handled exactly once. -
openAPI: improve schema for assets list response (#6622)
-
openApi: use proper query param name (#6664)
-
openapi: fix advancedfeaturesresponse schema (#6624)
-
openapi: advanced feature response action pr...
2.026.03f
What's Changed
Full Changelog: 2.026.03e...2.026.03f