Skip to content

Commit

Permalink
Copy the event data passed into LTIEvent.from_request to avoid modifi…
Browse files Browse the repository at this point in the history
…cations

Keep the original data verbatim safe for any modifications inside the
method.
  • Loading branch information
marcospri committed Jan 7, 2025
1 parent 33c86ed commit 70d97cf
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 8 deletions.
14 changes: 8 additions & 6 deletions lms/events/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ class LTIEvent(BaseEvent):
def from_request(
cls, request: Request, type_: EventType.Type, data: Mapping | None = None
):
# Create a copy of the data to avoid modifying the original
event_data = dict(data if data else {})

if not request.lti_user:
return cls(request=request, type=type_, data=data)
return cls(request=request, type=type_, data=event_data)

course_id = None
assignment_id = None
Expand All @@ -68,15 +71,14 @@ def from_request(
):
assignment_id = assignment.id

# Store the raw LTI parameters for launches
if type_ in {EventType.Type.CONFIGURED_LAUNCH, EventType.Type.DEEP_LINKING}:
# Store the raw LTI parameters for launches
data = {} if data is None else data
if request.lti_jwt:
# For LTI1.3 include the decoded JWT as a dict
data["lti_params"] = request.lti_jwt
event_data["lti_params"] = request.lti_jwt
else:
# For LTI1.1 include the request form parameters
data["lti_params"] = request.lti_params.serialize()
event_data["lti_params"] = request.lti_params.serialize()

return cls(
request=request,
Expand All @@ -86,7 +88,7 @@ def from_request(
application_instance_id=request.lti_user.application_instance_id,
course_id=course_id,
assignment_id=assignment_id,
data=data,
data=event_data,
)


Expand Down
6 changes: 4 additions & 2 deletions tests/unit/lms/events/event_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,19 @@ def test_lti_event_no_lti_user(self, pyramid_request):
assert not event.course_id
assert not event.assignment_id

@pytest.mark.parametrize("event_data", [None, {}, {"key": "value"}])
def test_lti_event(
self,
pyramid_request,
application_instance,
course_service,
assignment_service,
lti_user,
event_data,
):
lti_user.lti_roles = [sentinel]
event = LTIEvent.from_request(
request=pyramid_request, type_=sentinel.type, data=sentinel.data
request=pyramid_request, type_=sentinel.type, data=event_data
)

assert event.user_id == pyramid_request.user.id
Expand All @@ -75,7 +77,7 @@ def test_lti_event(
lti_user.tool_consumer_instance_guid, lti_user.lti.assignment_id
)
assert event.assignment_id == assignment_service.get_assignment.return_value.id
assert event.data == sentinel.data
assert event.data == (event_data if event_data else {})

def test_lti_event_when_no_course(self, pyramid_request, course_service):
course_service.get_by_context_id.return_value = None
Expand Down

0 comments on commit 70d97cf

Please sign in to comment.