Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lms/djangoapps/instructor/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2516,6 +2516,9 @@ def _list_instructor_tasks(request, course_id, serialize_data=None):
else:
# Specifying for single problem's history
tasks = task_api.get_instructor_task_history(course_id, module_state_key)
elif request.GET.get('include_canvas') is not None:
from ol_openedx_canvas_integration.task_helpers import get_filtered_instructor_tasks # pylint: disable=import-error
tasks = get_filtered_instructor_tasks(course_id, request.user)
else:
# If no problem or student, just get currently running tasks
tasks = task_api.get_running_instructor_tasks(course_id)
Expand Down
6 changes: 6 additions & 0 deletions lms/djangoapps/instructor_task/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ def get_task_completion_info(instructor_task): # lint-amnesty, pylint: disable=

student = None
problem_url = None
entrance_exam_url = None
email_id = None
task_input = None
try:
task_input = json.loads(instructor_task.task_input)
except ValueError:
Expand Down Expand Up @@ -192,6 +194,10 @@ def get_task_completion_info(instructor_task): # lint-amnesty, pylint: disable=
else: # num_succeeded < num_attempted
# Translators: {action} is a past-tense verb that is localized separately. {succeeded} and {attempted} are counts. # lint-amnesty, pylint: disable=line-too-long
msg_format = _("Problem {action} for {succeeded} of {attempted} students")
elif task_input and task_input.get('course_key'):
from ol_openedx_canvas_integration.utils import get_task_output_formatted_message # pylint: disable=import-error
msg_format = get_task_output_formatted_message(task_output)
succeeded = True
elif email_id is not None:
# this reports on actions on bulk emails
if num_attempted == 0:
Expand Down
53 changes: 51 additions & 2 deletions lms/djangoapps/lti_provider/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from django.test.client import RequestFactory
from django.urls import reverse
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from openedx_events.learning.data import UserData, UserPersonalData, LtiProviderLaunchData, LtiProviderLaunchParamsData

from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.courseware.testutils import RenderXBlockTestMixin
Expand Down Expand Up @@ -96,20 +97,42 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
"""
Tests for the lti_launch view
"""
@patch('lms.djangoapps.lti_provider.views.LTI_PROVIDER_LAUNCH_SUCCESS.send_event')
@patch('lms.djangoapps.lti_provider.views.render_courseware')
@patch('lms.djangoapps.lti_provider.views.authenticate_lti_user')
def test_valid_launch(self, _authenticate, render):
def test_valid_launch(self, _authenticate, render, lti_launch_success_send_event):
"""
Verifies that the LTI launch succeeds when passed a valid request.
"""
request = build_launch_request()
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
render.assert_called_with(request, USAGE_KEY)
lti_launch_success_send_event.assert_called_with(
launch_data=LtiProviderLaunchData(
user=UserData(
id=request.user.id,
is_active=request.user.is_active,
pii=UserPersonalData(
username=request.user.username,
email=request.user.email,
name=request.user.profile.name,
)
),
course_key=COURSE_KEY,
usage_key=USAGE_KEY,
launch_params=LtiProviderLaunchParamsData(
roles='Instructor,urn:lti:instrole:ims/lis/Administrator',
context_id='lti_launch_context_id',
user_id='LTI_User', extra_params={}
)
)
)
Comment on lines +110 to +129

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The assertion for extra_params is currently extra_params={}. However, based on the build_launch_request function (which populates the initial LTI parameters for the test) and the logic in lti_provider.views.lti_launch (which processes these parameters), several non-OAuth, non-explicitly-popped parameters should remain and be collected into extra_params.

Specifically, build_launch_request includes:

  • lis_result_sourcedid: 'test_sourcedid'
  • lis_outcome_service_url: 'test_url'
  • tool_consumer_instance_guid: 'test_guid'

These parameters are not OAuth parameters and are not among those explicitly popped (course_key, usage_key, roles, context_id, user_id) before constructing extra_params in the view. Therefore, they should be present in the extra_params dictionary.

Could you update the assertion to reflect the expected extra_params? This would make the test more accurately verify the behavior of the extra_params collection.

        lti_launch_success_send_event.assert_called_with(
            launch_data=LtiProviderLaunchData(
                user=UserData(
                    id=request.user.id,
                    is_active=request.user.is_active,
                    pii=UserPersonalData(
                        username=request.user.username,
                        email=request.user.email,
                        name=request.user.profile.name,
                    )
                ),
                course_key=COURSE_KEY,
                usage_key=USAGE_KEY,
                launch_params=LtiProviderLaunchParamsData(
                    roles='Instructor,urn:lti:instrole:ims/lis/Administrator',
                    context_id='lti_launch_context_id',
                    user_id='LTI_User', extra_params={
                        'lis_result_sourcedid': 'test_sourcedid',
                        'lis_outcome_service_url': 'test_url',
                        'tool_consumer_instance_guid': 'test_guid'
                    }
                )
            )
        )

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

build_launch_request takes an extra_post_data if that is blank then no extra params will be added and extra_params will be empty as it is in the reviewed code.


@patch('lms.djangoapps.lti_provider.views.LTI_PROVIDER_LAUNCH_SUCCESS.send_event')
@patch('lms.djangoapps.lti_provider.views.render_courseware')
@patch('lms.djangoapps.lti_provider.views.store_outcome_parameters')
@patch('lms.djangoapps.lti_provider.views.authenticate_lti_user')
def test_valid_launch_with_optional_params(self, _authenticate, store_params, _render):
def test_valid_launch_with_optional_params(self, _authenticate, store_params, _render, lti_launch_success_send_event):
"""
Verifies that the LTI launch succeeds when passed a valid request.
"""
Expand All @@ -120,6 +143,32 @@ def test_valid_launch_with_optional_params(self, _authenticate, store_params, _r
request.user,
self.consumer
)
lti_launch_success_send_event.assert_called_with(
launch_data=LtiProviderLaunchData(
user=UserData(
id=request.user.id,
is_active=request.user.is_active,
pii=UserPersonalData(
username=request.user.username,
email=request.user.email,
name=request.user.profile.name,
)
),
course_key=COURSE_KEY,
usage_key=USAGE_KEY,
launch_params=LtiProviderLaunchParamsData(
roles='Instructor,urn:lti:instrole:ims/lis/Administrator',
context_id='lti_launch_context_id',
user_id='LTI_User', extra_params={
'context_title': 'context title',
'context_label': 'context label',
'lis_result_sourcedid': 'result sourcedid',
'lis_outcome_service_url': 'outcome service URL',
'tool_consumer_instance_guid': 'consumer instance guid',
}
)
)
)

@patch('lms.djangoapps.courseware.views.views.render_xblock')
@patch('lms.djangoapps.lti_provider.views.authenticate_lti_user')
Expand Down
30 changes: 30 additions & 0 deletions lms/djangoapps/lti_provider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from common.djangoapps.edxmako.shortcuts import render_to_response
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey, UsageKey
from openedx_events.learning.data import LtiProviderLaunchData, LtiProviderLaunchParamsData, UserData, UserPersonalData
from openedx_events.learning.signals import LTI_PROVIDER_LAUNCH_SUCCESS

from common.djangoapps.util.views import add_p3p_header
from lms.djangoapps.lti_provider.models import LtiConsumer
Expand Down Expand Up @@ -107,6 +109,34 @@ def lti_launch(request, course_id, usage_id):
# used earlier to verify the oauth signature.
store_outcome_parameters(params, request.user, lti_consumer)

# Make a copy of params for the event signal, and remove sensitive oauth parameters.
launch_params = params.copy()
for key in list(launch_params.keys()):
if key.startswith('oauth_'):
launch_params.pop(key)

LTI_PROVIDER_LAUNCH_SUCCESS.send_event(
launch_data=LtiProviderLaunchData(
user=UserData(
pii=UserPersonalData(
username=request.user.username,
email=request.user.email,
name=request.user.profile.name,
),
id=request.user.id,
is_active=request.user.is_active,
),
course_key=launch_params.pop("course_key"),
usage_key=launch_params.pop("usage_key"),
launch_params=LtiProviderLaunchParamsData(
roles=launch_params.pop("roles"),
context_id=launch_params.pop("context_id"),
user_id=launch_params.pop("user_id"),
extra_params={key: str(val) for key, val in launch_params.items()},
),
)
)

return render_courseware(request, params['usage_key'])


Expand Down
3 changes: 3 additions & 0 deletions lms/static/js/instructor_dashboard/instructor_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ such that the value can be defined later than this assignment (file load order).
}, {
constructor: window.InstructorDashboard.sections.ECommerce,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#e-commerce')
}, {
constructor: window.InstructorDashboard.sections.CanvasIntegration,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#canvas_integration')
}, {
constructor: window.InstructorDashboard.sections.Membership,
$element: idashContent.find('.' + CSS_IDASH_SECTION + '#membership')
Expand Down
6 changes: 4 additions & 2 deletions lms/static/js/instructor_dashboard/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
enableColumnReorder: false,
autoHeight: true,
rowHeight: 100,
forceFitColumns: true
forceFitColumns: true,
enableTextSelectionOnCells: true
};
columns = [
{
Expand Down Expand Up @@ -492,7 +493,8 @@
enableCellNavigation: true,
enableColumnReorder: false,
rowHeight: 30,
forceFitColumns: true
forceFitColumns: true,
enableTextSelectionOnCells: true
};
columns = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,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>
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

## Include Underscore templates
<%block name="header_extras">
% for template_name in ["cohorts", "discussions", "enrollment-code-lookup-links", "cohort-editor", "cohort-group-header", "cohort-selector", "cohort-form", "notification", "cohort-state", "divided-discussions-inline", "divided-discussions-course-wide", "cohort-discussions-category", "cohort-discussions-subcategory", "certificate-allowlist", "certificate-allowlist-editor", "certificate-bulk-allowlist", "certificate-invalidation", "membership-list-widget"]:
% for template_name in ["cohorts", "discussions", "enrollment-code-lookup-links", "cohort-editor", "cohort-group-header", "cohort-selector", "cohort-form", "notification", "cohort-state", "divided-discussions-inline", "divided-discussions-course-wide", "cohort-discussions-category", "cohort-discussions-subcategory", "certificate-allowlist", "certificate-allowlist-editor", "certificate-bulk-allowlist", "certificate-invalidation", "membership-list-widget", "html-datatable"]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="instructor/instructor_dashboard_2/${template_name}.underscore" />
</script>
Expand Down
2 changes: 2 additions & 0 deletions requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,5 @@ elasticsearch==7.9.1
# https://github.com/openedx/edx-platform/issues/36425
xmlsec==1.3.14
social-auth-core==4.5.4

openedx-events @ git+https://github.com/open-craft/openedx-events.git@kshitij/lti-launch-event

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This change pins openedx-events to a specific branch. While this is fine for development, it's important to ensure this is updated to a released version before merging to a stable branch or for a release. This ensures that the platform is using stable, tested code and not code that is still under development.

openedx-events==10.2.0

3 changes: 2 additions & 1 deletion requirements/edx/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -801,8 +801,9 @@ openedx-django-require==2.1.0
# via -r requirements/edx/kernel.in
openedx-django-wiki==2.1.0
# via -r requirements/edx/kernel.in
openedx-events==10.2.0
openedx-events @ git+https://github.com/open-craft/openedx-events.git@kshitij/lti-launch-event

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This change pins openedx-events to a specific branch. While this is fine for development, it's important to ensure this is updated to a released version before merging to a stable branch or for a release. This ensures that the platform is using stable, tested code and not code that is still under development.

openedx-events==10.2.0

# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/kernel.in
# edx-enterprise
# edx-event-bus-kafka
Expand Down
3 changes: 2 additions & 1 deletion requirements/edx/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1358,8 +1358,9 @@ openedx-django-wiki==2.1.0
# via
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
openedx-events==10.2.0
openedx-events @ git+https://github.com/open-craft/openedx-events.git@kshitij/lti-launch-event

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This change pins openedx-events to a specific branch. While this is fine for development, it's important to ensure this is updated to a released version before merging to a stable branch or for a release. This ensures that the platform is using stable, tested code and not code that is still under development.

openedx-events==10.2.0

# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/doc.txt
# -r requirements/edx/testing.txt
# edx-enterprise
Expand Down
3 changes: 2 additions & 1 deletion requirements/edx/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -972,8 +972,9 @@ openedx-django-require==2.1.0
# via -r requirements/edx/base.txt
openedx-django-wiki==2.1.0
# via -r requirements/edx/base.txt
openedx-events==10.2.0
openedx-events @ git+https://github.com/open-craft/openedx-events.git@kshitij/lti-launch-event

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This change pins openedx-events to a specific branch. While this is fine for development, it's important to ensure this is updated to a released version before merging to a stable branch or for a release. This ensures that the platform is using stable, tested code and not code that is still under development.

openedx-events==10.2.0

# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
# edx-event-bus-kafka
Expand Down
3 changes: 2 additions & 1 deletion requirements/edx/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1030,8 +1030,9 @@ openedx-django-require==2.1.0
# via -r requirements/edx/base.txt
openedx-django-wiki==2.1.0
# via -r requirements/edx/base.txt
openedx-events==10.2.0
openedx-events @ git+https://github.com/open-craft/openedx-events.git@kshitij/lti-launch-event

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This change pins openedx-events to a specific branch. While this is fine for development, it's important to ensure this is updated to a released version before merging to a stable branch or for a release. This ensures that the platform is using stable, tested code and not code that is still under development.

openedx-events==10.2.0

# via
# -c requirements/edx/../constraints.txt
# -r requirements/edx/base.txt
# edx-enterprise
# edx-event-bus-kafka
Expand Down