Skip to content

Hotfixes release v2025.08.14 - #5300

Merged
bjester merged 851 commits into
hotfixesfrom
unstable
Aug 22, 2025
Merged

bjester merged 851 commits into
hotfixesfrom
unstable

Conversation

@bjester

@bjester bjester commented Aug 14, 2025 •

Copy link
Copy Markdown
Member

Summary

PR Issues Category QA Focus
#5083 #5063 Enhancement Trigger data export from Account settings
#5088 #5057, #5058, #5088 Enhancement Interact and provide feedback on Search recommendations
#5097 #5124 Enhancement (skip)
#5103 #4878 Enhancement Publish a channel
#5106 #5093 Enhancement Visual check of modal headers
#5125 #5111 Enhancement Change folder language before using
import modal for importing search recommendations
#5126 #5116 Enhancement Browse search recommendations
#5128 #5042 Enhancement Edit a channel and resources with grade levels
#5144 #5115 Enhancement (skip)
#5149 N/A Enhancement Preview a resource
#5155 #5131, #5146, #2178 Enhancement (skip)
#5248 #5069 Enhancement Deploy staged channel
#5253 #5211, #4086 Enhancement Review selected resources in import modal
#5255 N/A Enhancement Review selected resources in import modal
#5261 N/A Enhancement Browse search recommendations
#5040 N/A Bug fix N/A
#5104 #4073 Bug fix View channel details
#5147 #5065 Bug fix N/A
#5102 #5068 Tech Debt N/A
#4902 N/A DevOps N/A
#5105 N/A DevOps N/A
#5134 N/A DevOps N/A
#5143 N/A DevOps N/A
#5177 N/A DevOps N/A
#5190 N/A DevOps N/A
#5196 N/A DevOps N/A
#5197 N/A DevOps N/A
#5254 N/A DevOps N/A
#5293 N/A DevOps N/A
Dependency PRs
PR Category
#5076 Dependency
#5084 Dependency
#5085 Dependency
#5086 Dependency
#5096 Dependency
#5098 Dependency
#5099 Dependency
#5108 Dependency
#5113 Dependency
#5117 Dependency
#5119 Dependency
#5120 Dependency
#5121 Dependency
#5136 Dependency
#5137 Dependency
#5139 Dependency
#5141 Dependency
#5148 Dependency
#5152 Dependency
#5154 Dependency
#5164 Dependency
#5179 Dependency
#5181 Dependency
#5182 Dependency
#5198 Dependency
#5199 Dependency
#5200 Dependency
#5201 Dependency
#5202 Dependency
#5203 Dependency
#5204 Dependency
#5205 Dependency
#5207 Dependency
#5210 Dependency
#5223 Dependency
#5224 Dependency
#5226 Dependency
#5238 Dependency
#5239 Dependency
#5256 Dependency

AlexVelezLl and others added 30 commits June 11, 2025 16:41
in favor of default templates
from .github repo
in favor of the default .github CONTRIBUTING.md
Improve clarity and remove dependencies
of tests on wrapper internal implementation
Remove custom issue templates, turn on issue header automation, reference new contributing guidelines
…n/babel-f525feed9f

Bump the babel group with 4 updates
…ema-4.24.0

Bump jsonschema from 4.23.0 to 4.24.0
…s-2.32.4

Bump requests from 2.32.3 to 2.32.4
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.0 to 5.2.2.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](webpack/webpack-dev-server@v5.2.0...v5.2.2)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
AlexVelezLl and others added 16 commits August 6, 2025 09:46
Confirm None handling for attribution fields.
Add thumbnail placeholder to recommendation card
…sdk-2.34.1

chore(deps): bump sentry-sdk from 2.34.0 to 2.34.1
Bumps [redis](https://github.com/redis/redis-py) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](redis/redis-py@v6.2.0...v6.3.0)

---
updated-dependencies:
- dependency-name: redis
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
….3.0

chore(deps): bump redis from 6.2.0 to 6.3.0
…ls-7.5.0

chore(deps-dev): bump pip-tools from 7.4.1 to 7.5.0
…n/eslint-config-prettier-10.1.8

chore(deps-dev): bump eslint-config-prettier from 10.1.5 to 10.1.8
…n/node-vibrant-4.0.3

chore(deps): bump node-vibrant from 3.1.6 to 4.0.3
Ensure that file_format and preset match during file_upload requests.
Improve query that checks storage space before channel deploy
* Updated collection link and modal in channelSetList

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Comment on lines +9 to +14
uses: learningequality/.github/.github/workflows/contributor-issue-comment.yml@main
secrets:
LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }}
LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_COMMUNITY_NOTIFICATIONS_WEBHOOK_URL: ${{ secrets.SLACK_COMMUNITY_NOTIFICATIONS_WEBHOOK_URL }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +9 to +13
name: Call shared workflow
uses: learningequality/.github/.github/workflows/manage-issue-header.yml@main
secrets:
LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }}
LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +9 to +12
uses: learningequality/.github/.github/workflows/community-contribution-label.yml@main
secrets:
LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }}
LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +17 to +28
name: Path match check
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }}
steps:
- id: skip_check
uses: fkirc/skip-duplicate-actions@master
with:
github_token: ${{ github.token }}
paths_ignore: '["**.po", "**.json"]'
linting:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +29 to +52
name: All file linting
needs: pre_job
if: ${{ needs.pre_job.outputs.should_skip != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Use pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'pnpm'
- name: Install dependencies
run: |
pnpm install --frozen-lockfile
pnpm rebuild node-sass
- uses: pre-commit/action@v3.0.1
- name: Run pre-commit-ci-lite
uses: pre-commit-ci/lite-action@v1.1.0
if: always()

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{contents: read}}
Comment on lines +11 to +15
uses: learningequality/.github/.github/workflows/unassign-inactive-issues.yaml@main
secrets:
LE_BOT_APP_ID: ${{ secrets.LE_BOT_APP_ID }}
LE_BOT_PRIVATE_KEY: ${{ secrets.LE_BOT_PRIVATE_KEY }}
SLACK_COMMUNITY_NOTIFICATIONS_WEBHOOK_URL: ${{ secrets.SLACK_COMMUNITY_NOTIFICATIONS_WEBHOOK_URL }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +8 to +12
uses: learningequality/.github/.github/workflows/update-pr-spreadsheet.yml@main
secrets:
CONTRIBUTIONS_SPREADSHEET_ID: ${{ secrets.CONTRIBUTIONS_SPREADSHEET_ID }}
CONTRIBUTIONS_SHEET_NAME: ${{ secrets.CONTRIBUTIONS_SHEET_NAME }}
GH_UPLOADER_GCP_SA_CREDENTIALS: ${{ secrets.GH_UPLOADER_GCP_SA_CREDENTIALS }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}
Comment on lines +195 to +197
"\n\n\nSETUP DONE: Log in as admin to view data (email: {}, password: {})\n\n\n".format(
email, password
)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information

This expression logs [sensitive data (password)](1) as clear text.

Copilot Autofix

AI about 1 year ago

To fix the problem, we should avoid logging the password in clear text. The best approach is to remove the password from the printed message entirely. If it's necessary to inform the user about the credentials, only the email (username) should be shown, and the password can be omitted or replaced with a placeholder (e.g., "[hidden]"). This change should be made in the print statement on lines 195–197 in contentcuration/contentcuration/management/commands/setup.py. No additional imports or methods are needed.


Suggested changeset 1
contentcuration/contentcuration/management/commands/setup.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/management/commands/setup.py b/contentcuration/contentcuration/management/commands/setup.py
--- a/contentcuration/contentcuration/management/commands/setup.py
+++ b/contentcuration/contentcuration/management/commands/setup.py
@@ -192,8 +192,8 @@
                 legacy_node.copy_to(target=user1.clipboard_tree)
 
         print(  # noqa: T201
-            "\n\n\nSETUP DONE: Log in as admin to view data (email: {}, password: {})\n\n\n".format(
-                email, password
+            "\n\n\nSETUP DONE: Log in as admin to view data (email: {})\n\n\n".format(
+                email
             )
         )
 
EOF
@@ -192,8 +192,8 @@
legacy_node.copy_to(target=user1.clipboard_tree)

print( # noqa: T201
"\n\n\nSETUP DONE: Log in as admin to view data (email: {}, password: {})\n\n\n".format(
email, password
"\n\n\nSETUP DONE: Log in as admin to view data (email: {})\n\n\n".format(
email
)
)

Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread contentcuration/contentcuration/urls.py Fixed
md5.update((channel_id or '').encode('utf-8'))
md5.update(task_name.encode("utf-8"))
md5.update((task_kwargs or "").encode("utf-8"))
md5.update((channel_id or "").encode("utf-8"))

Check failure

Code scanning / CodeQL

Use of a broken or weak cryptographic hashing algorithm on sensitive data

[Sensitive data (id)](1) is used in a hashing algorithm (MD5) that is insecure.

Copilot Autofix

AI about 1 year ago

To fix the problem, replace the use of MD5 in generate_task_signature with a strong cryptographic hash function, such as SHA-256. This involves changing the instantiation of the hash object from hashlib.md5() to hashlib.sha256(), and updating the docstring to reflect the new hash algorithm. Only the code in contentcuration/contentcuration/utils/celery/tasks.py needs to be changed, specifically the generate_task_signature function (lines 82-96). No other code changes are required, as the function's output format (hexdigest()) remains the same.


Suggested changeset 1
contentcuration/contentcuration/utils/celery/tasks.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/utils/celery/tasks.py b/contentcuration/contentcuration/utils/celery/tasks.py
--- a/contentcuration/contentcuration/utils/celery/tasks.py
+++ b/contentcuration/contentcuration/utils/celery/tasks.py
@@ -85,14 +85,14 @@
     :param task_kwargs: the celery encoded/serialized form of the task_kwargs dict
     :type task_kwargs: str|None
     :type channel_id: str|None
-    :return: A hex string, md5
+    :return: A hex string, sha256
     :rtype: str
     """
-    md5 = hashlib.md5()
-    md5.update(task_name.encode("utf-8"))
-    md5.update((task_kwargs or "").encode("utf-8"))
-    md5.update((channel_id or "").encode("utf-8"))
-    return md5.hexdigest()
+    sha256 = hashlib.sha256()
+    sha256.update(task_name.encode("utf-8"))
+    sha256.update((task_kwargs or "").encode("utf-8"))
+    sha256.update((channel_id or "").encode("utf-8"))
+    return sha256.hexdigest()
 
 
 class CeleryTask(Task):
EOF
@@ -85,14 +85,14 @@
:param task_kwargs: the celery encoded/serialized form of the task_kwargs dict
:type task_kwargs: str|None
:type channel_id: str|None
:return: A hex string, md5
:return: A hex string, sha256
:rtype: str
"""
md5 = hashlib.md5()
md5.update(task_name.encode("utf-8"))
md5.update((task_kwargs or "").encode("utf-8"))
md5.update((channel_id or "").encode("utf-8"))
return md5.hexdigest()
sha256 = hashlib.sha256()
sha256.update(task_name.encode("utf-8"))
sha256.update((task_kwargs or "").encode("utf-8"))
sha256.update((channel_id or "").encode("utf-8"))
return sha256.hexdigest()


class CeleryTask(Task):
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread contentcuration/contentcuration/utils/files.py Fixed

Check warning

Code scanning / CodeQL

Construction of a cookie using user-supplied input

Cookie is constructed from a [user-supplied input](1).

Copilot Autofix

AI about 1 year ago

To fix the problem, we should ensure that only valid, expected language codes are used to set the cookie. The best way is to check that lang_code is in the set of allowed language codes defined in Django's settings (settings.LANGUAGES). This is stricter than relying on check_for_language, which may allow any language code that Django can process, including custom or unexpected values. The fix should be applied in the set_language view, specifically before setting the cookie. We need to import settings.LANGUAGES if not already available, and add a check that lang_code is in the allowed set before calling set_cookie. If not, we should fall back to a default language or avoid setting the cookie.


Suggested changeset 1
contentcuration/contentcuration/views/base.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/views/base.py b/contentcuration/contentcuration/views/base.py
--- a/contentcuration/contentcuration/views/base.py
+++ b/contentcuration/contentcuration/views/base.py
@@ -403,7 +403,8 @@
         next_url = translate_url(reverse("base"), lang_code)
     response = HttpResponse(next_url) if next_url else HttpResponse(status=204)
     if request.method == "POST":
-        if lang_code and check_for_language(lang_code):
+        allowed_lang_codes = {code for code, _ in settings.LANGUAGES}
+        if lang_code and check_for_language(lang_code) and lang_code in allowed_lang_codes:
             if next_url:
                 next_trans = translate_url(next_url, lang_code)
                 if next_trans != next_url:
EOF
@@ -403,7 +403,8 @@
next_url = translate_url(reverse("base"), lang_code)
response = HttpResponse(next_url) if next_url else HttpResponse(status=204)
if request.method == "POST":
if lang_code and check_for_language(lang_code):
allowed_lang_codes = {code for code, _ in settings.LANGUAGES}
if lang_code and check_for_language(lang_code) and lang_code in allowed_lang_codes:
if next_url:
next_trans = translate_url(next_url, lang_code)
if next_trans != next_url:
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
Comment thread contentcuration/contentcuration/views/zip.py Fixed
Comment thread contentcuration/kolibri_public/views_v1.py Fixed
Comment thread contentcuration/kolibri_public/views_v1.py Fixed
Comment thread contentcuration/kolibri_public/views_v1.py Fixed
Comment thread contentcuration/kolibri_public/views_v1.py Fixed
Address user-supplied CodeQL issues
)
except KeyError as e:
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))

Check warning

Code scanning / CodeQL

Information exposure through an exception

[Stack trace information](1) flows to this location and may be exposed to an external user.

Copilot Autofix

AI about 1 year ago

To avoid revealing potentially sensitive internal information, the handler for KeyError in the api_create_channel_endpoint function should not return the string representation of the exception object as part of the HTTP error response. Instead, it should return a generic error message (e.g., "Required attribute missing from data"), optionally logging the actual exception server-side for debugging. This involves editing lines 224–227 to remove str(e) from the response message, and possibly adding a server-side logging call for the exception.

  • Change the return value of the except KeyError as e: block to a generic message: "Required attribute missing from data".
  • Optionally, log the error (using logging.exception or similar).
  • Do not include the missing key name or stringified exception in the HTTP response body.
Suggested changeset 1
contentcuration/contentcuration/views/internal.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/views/internal.py b/contentcuration/contentcuration/views/internal.py
--- a/contentcuration/contentcuration/views/internal.py
+++ b/contentcuration/contentcuration/views/internal.py
@@ -222,9 +222,8 @@
             }
         )
     except KeyError as e:
-        return HttpResponseBadRequest(
-            "Required attribute missing from data | {}".format(str(e))
-        )
+        logging.exception("Missing required attribute in channel create request.")
+        return HttpResponseBadRequest("Required attribute missing from data")
     except Exception as e:
         handle_server_error(e, request)
         return HttpResponseServerError(content=str(e), reason=str(e))
EOF
@@ -222,9 +222,8 @@
}
)
except KeyError as e:
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))
)
logging.exception("Missing required attribute in channel create request.")
return HttpResponseBadRequest("Required attribute missing from data")
except Exception as e:
handle_server_error(e, request)
return HttpResponseServerError(content=str(e), reason=str(e))
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
return HttpResponseBadRequest("Required attribute missing from data: {}".format(data))
except KeyError as e:
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))

Check warning

Code scanning / CodeQL

Information exposure through an exception

[Stack trace information](1) flows to this location and may be exposed to an external user.

Copilot Autofix

AI about 1 year ago

To fix the problem, the function should return a generic error message to the client when a KeyError is caught, rather than interpolating the exception message which can leak information about internal variable names or input data structure. The actual error details (including the exception message) should be recorded in logs and/or sent to Sentry for developer diagnostics.

Detailed steps:

  • Replace the except KeyError as e: block such that it logs or reports the error (using the existing handle_server_error or report_exception methods, as appropriate).
  • The HTTP response should return a generic error message like "Required attribute missing from data" without any dynamic content (i.e., do not interpolate str(e) into the message).

Files/lines to change:

  • Only make changes inside contentcuration/contentcuration/views/internal.py within the api_commit_channel function and do not alter code that is not shown.
  • Add logging/reporting of the actual exception for admin/developer reference.

Suggested changeset 1
contentcuration/contentcuration/views/internal.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/views/internal.py b/contentcuration/contentcuration/views/internal.py
--- a/contentcuration/contentcuration/views/internal.py
+++ b/contentcuration/contentcuration/views/internal.py
@@ -295,8 +295,9 @@
     except (Channel.DoesNotExist, PermissionDenied):
         return HttpResponseNotFound("No channel matching: {}".format(channel_id))
     except KeyError as e:
+        handle_server_error(e, request)
         return HttpResponseBadRequest(
-            "Required attribute missing from data | {}".format(str(e))
+            "Required attribute missing from data"
         )
     except Exception as e:
         handle_server_error(e, request)
EOF
@@ -295,8 +295,9 @@
except (Channel.DoesNotExist, PermissionDenied):
return HttpResponseNotFound("No channel matching: {}".format(channel_id))
except KeyError as e:
handle_server_error(e, request)
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))
"Required attribute missing from data"
)
except Exception as e:
handle_server_error(e, request)
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
return HttpResponseBadRequest("Required attribute missing from data: {}".format(data))
except KeyError as e:
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))

Check warning

Code scanning / CodeQL

Information exposure through an exception

[Stack trace information](1) flows to this location and may be exposed to an external user.

Copilot Autofix

AI about 1 year ago

The best fix is to replace the HttpResponseBadRequest in the except KeyError as e: block so that it does not return the exception detail (str(e)) to the user. Instead, it should return a generic "Required attribute missing from request data" message. The detail can be logged server-side using the Python logging module or sent to Sentry if available.

Specifically:

  • In api_add_nodes_to_tree (lines ~354-357), replace the return statement so the user response does not include str(e).
  • Optionally, add a call to logging.error() (or use the existing Sentry report facility as imported) to capture the original exception detail for diagnostics.
  • No additional dependencies are needed, as logging is already imported and Sentry reporting appears available.
  • No changes outside this block are required.

Suggested changeset 1
contentcuration/contentcuration/views/internal.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/contentcuration/contentcuration/views/internal.py b/contentcuration/contentcuration/views/internal.py
--- a/contentcuration/contentcuration/views/internal.py
+++ b/contentcuration/contentcuration/views/internal.py
@@ -352,9 +352,8 @@
     except ValidationError as e:
         return HttpResponseBadRequest(content=str(e))
     except KeyError as e:
-        return HttpResponseBadRequest(
-            "Required attribute missing from data | {}".format(str(e))
-        )
+        logging.error("Required attribute missing in api_add_nodes_to_tree: %s", str(e))
+        return HttpResponseBadRequest("Required attribute missing from request data")
     except NodeValidationError as e:
         return HttpResponseBadRequest(str(e))
     except Exception as e:
EOF
@@ -352,9 +352,8 @@
except ValidationError as e:
return HttpResponseBadRequest(content=str(e))
except KeyError as e:
return HttpResponseBadRequest(
"Required attribute missing from data | {}".format(str(e))
)
logging.error("Required attribute missing in api_add_nodes_to_tree: %s", str(e))
return HttpResponseBadRequest("Required attribute missing from request data")
except NodeValidationError as e:
return HttpResponseBadRequest(str(e))
except Exception as e:
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
rtibbles and others added 2 commits August 21, 2025 15:33
…are KA only markdown elements.

Ensure relative path is used during QTI item generation.
Fix image export in QTI exercise publishing

@rtibbles rtibbles left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's hotfix this!

@bjester
bjester merged commit 71eef1b into hotfixes Aug 22, 2025
@bjester bjester mentioned this pull request Aug 22, 2025
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.