Skip to content

Conversation

@xitij2000
Copy link

Cherry-pick of : openedx#37262

@sentry
Copy link

sentry bot commented Aug 27, 2025

🔍 Existing Issues For Review

Your pull request is modifying functions with the following pre-existing issues:

📄 File: lms/djangoapps/lti_provider/views.py

Function Unhandled Issue
lti_launch AttributeError: 'NoneType' object has no attribute 'lower' /lti_provider/courses/{course_id}[/+]+{var}[/]+)/{usage...
Event Count: 71

Did you find this useful? React with a 👍 or 👎

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @xitij2000, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily introduces the capability to define and process custom LTI (Learning Tools Interoperability) parameters within the platform. This enhancement allows for greater flexibility when integrating with external LTI tools by enabling the inclusion of additional, user-defined data during LTI launches. Beyond the core LTI feature, the PR also includes updates to the instructor dashboard, specifically adding support for Canvas integration-related tasks and making minor UI improvements to data tables.

Highlights

  • Custom LTI Parameters: Introduced a new Django setting, LTI_CUSTOM_PARAMS, which allows administrators to define a list of custom LTI parameters that the platform should recognize and process during an LTI launch.
  • LTI Launch Processing: Modified the LTI launch view to extract and store these newly defined custom parameters, ensuring they are available for other plugins or integrations.
  • LTI Parameter Testing: Added a dedicated test case to validate that the system correctly handles LTI launches with custom parameters, confirming the new functionality works as expected.
  • Instructor Dashboard & Canvas Integration: Integrated new functionality related to Canvas integration within the instructor dashboard, including filtering tasks and formatting messages based on Canvas-specific data.
  • Frontend Improvements: Enhanced the instructor dashboard's user interface by enabling text selection within data tables and adding a new generic HTML data table template.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new feature to allow custom LTI parameters to be passed during an LTI launch, configured via the LTI_CUSTOM_PARAMS Django setting. This is a useful extension for plugins that need to receive extra information. The changes include the core logic in the LTI provider view, a new setting, and corresponding tests. Additionally, there are several changes related to a Canvas integration, including updates to the instructor dashboard and task views.

My review focuses on improving code clarity, correctness, and maintainability. I've pointed out an opportunity to simplify test code, corrected a type hint and a misleading docstring in the new LTI parameter handling function, and fixed invalid HTML in a new template. These changes will help ensure the new code is robust and easy to understand.

Comment on lines +134 to +138
store_params.assert_called_with(
dict(list(ALL_PARAMS.items()) + list(LTI_OPTIONAL_PARAMS.items()) + list(extra_params.items())),
request.user,
self.consumer
)

Choose a reason for hiding this comment

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

medium

The dictionary construction for the assertion is a bit verbose. Since you're using the | operator for dictionary union on line 132, you could use it here as well to make the code more concise and readable.

Suggested change
store_params.assert_called_with(
dict(list(ALL_PARAMS.items()) + list(LTI_OPTIONAL_PARAMS.items()) + list(extra_params.items())),
request.user,
self.consumer
)
store_params.assert_called_with(
ALL_PARAMS | LTI_OPTIONAL_PARAMS | extra_params,
request.user,
self.consumer
)

Comment on lines +150 to +159
def get_custom_parameters(params: dict[str]) -> dict[str]:
"""
Extract all optional LTI parameters from a dictionary. This method does not
fail if any parameters are missing.
:param params: A dictionary containing zero or more parameters.
:return: A new dictionary containing all optional parameters from the
original dictionary, or an empty dictionary if no optional parameters
were present.
"""

Choose a reason for hiding this comment

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

medium

The type hint for params is invalid. It should be dict[str, str] since request.POST values are strings. Also, the docstring seems to be a copy-paste from get_optional_parameters and is misleading. It should refer to "custom" LTI parameters, not "optional" ones, to avoid confusion.

Suggested change
def get_custom_parameters(params: dict[str]) -> dict[str]:
"""
Extract all optional LTI parameters from a dictionary. This method does not
fail if any parameters are missing.
:param params: A dictionary containing zero or more parameters.
:return: A new dictionary containing all optional parameters from the
original dictionary, or an empty dictionary if no optional parameters
were present.
"""
def get_custom_parameters(params: dict[str, str]) -> dict[str, str]:
"""
Extract all custom LTI parameters from a dictionary. This method does not
fail if any parameters are missing.
:param params: A dictionary containing zero or more parameters.
:return: A new dictionary containing all custom parameters from the
original dictionary, or an empty dictionary if no custom parameters
were present.
"""

Comment on lines +1 to +16
<p>
<h2><%- title %></h2>
<table class="stat_table"><tr>
<%_.forEach(header, function (h) {%>
<th><%- h %></th>
<%})%>
</tr>
<%_.forEach(data, function (row) {%>
<tr>
<%_.forEach(row, function (value) {%>
<td><%- value %></td>
<%})%>
</tr>
<%})%>
</table>
</p>

Choose a reason for hiding this comment

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

medium

The HTML structure is invalid because an <h2> element cannot be a direct child of a <p> element. This can lead to unpredictable rendering in some browsers. You should use a <div> as the container instead.

<div>
    <h2><%- title %></h2>
    <table class="stat_table"><tr>
        <%_.forEach(header, function (h) {%>
            <th><%- h %></th>
        <%})%>
        </tr>
        <%_.forEach(data, function (row) {%>
            <tr>
                <%_.forEach(row, function (value) {%>
                    <td><%- value %></td>
                <%})%>
            </tr>
        <%})%>
    </table>
</div>

@xitij2000 xitij2000 force-pushed the kshitij/lti-launch-optional-teak branch from fea8dd8 to 6c683ad Compare August 27, 2025 09:34
@xitij2000 xitij2000 force-pushed the kshitij/lti-launch-optional-teak branch from 6c683ad to a224971 Compare August 28, 2025 11:55
Copy link

@farhaanbukhsh farhaanbukhsh left a comment

Choose a reason for hiding this comment

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

👍

  • ✅ I tested this with tutor devstack
  • ✅ I read through the code
  • ❌ I checked for accessibility issues
  • ❌ Includes documentation

arslanashraf7 and others added 2 commits September 2, 2025 12:26
* feat: add canvas integration support

(cherry picked from commit fdb818a)
When dealing with subsections that have a lot of units, show a dropdown for
unit selection to simplify navigation.

(cherry picked from commit aaca11f)
… setting

Adds a new Django setting called `LTI_CUSTOM_PARAMS` that allows extending the
list of optional LTI parameters processed by the platform. These parameters can
be used by plugins for deeper platform integration.

(cherry picked from commit 0fde8c2)
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.

3 participants