Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: GET endpoint to retrieve message history #119

Merged
merged 14 commits into from
Oct 31, 2024
Merged

Conversation

ilee2u
Copy link
Member

@ilee2u ilee2u commented Oct 25, 2024

Ticket: https://2u-internal.atlassian.net/browse/COSMO-434

Add GET endpoint to learning-assistant to retrieve message history for a user/course combination.

  • Should get messages by user/course combination
  • Should add query parameter to limit the amount of messages we receive

learning_assistant/views.py Outdated Show resolved Hide resolved
learning_assistant/views.py Outdated Show resolved Hide resolved
learning_assistant/urls.py Outdated Show resolved Hide resolved
enrollment_object = CourseEnrollment.get_enrollment(request.user, courserun_key)
enrollment_mode = enrollment_object.mode if enrollment_object else None
if (
(enrollment_mode not in CourseMode.VERIFIED_MODES)
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure this logic condition is correct?
We should return if user_role_is_staff, no?
Are you sure we don't want to show message history to audit mode learners?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not quite sure, I copy/pasted this from another view so this could be wrong. @alangsto Do you have an opinion on this?

learning_assistant/api.py Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Oct 29, 2024

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  learning_assistant
  __init__.py
  api.py
  text_utils.py
  urls.py
  views.py 191-192
Project Total  

This report was generated by python-coverage-comment-action

Copy link
Member

@varshamenon4 varshamenon4 left a comment

Choose a reason for hiding this comment

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

Looks good so far! A couple of questions/comments!

"""
Given a course run id (str), user (User), and message count (int), return the associated message history.

Returns a number of messages equal to the message_count value.
Copy link
Member

Choose a reason for hiding this comment

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

Nit: If the message count exceeds the number of messages, we could return messages that are less than this value (in other words, the number of messages cannot exceed this value but could be less than this value).

Returns a number of messages equal to the message_count value.
"""
message_history = LearningAssistantMessage.objects.filter(
course_id=course_id, user=user).order_by('-created')[:message_count]
Copy link
Member

Choose a reason for hiding this comment

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

Would we need the handle the case here if the message count exceeds the number of messages? (i.e. to prevent and index error)

)

# If user does not have an enrollment record, or is not staff, they should not have access
# NOTE: Do we need this? Do we currently not have any plans to show message history to audit mode learners?
Copy link
Member

Choose a reason for hiding this comment

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

I think we do want to have this logic for now and then will adjust once we add the audit experience work. We'll need to have logic to limit access to audit learners.

authentication_classes = (SessionAuthentication, JwtAuthentication,)
permission_classes = (IsAuthenticated,)

def get(self, request, course_run_id, message_count):
Copy link
Member

Choose a reason for hiding this comment

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

I think the message count should be a query parameter, not a path parameter. If no message count is provided as a query parameter, we should have a default value.


course_id = get_course_id(course_run_id)
user = request.user
data = get_message_history(course_id, user, message_count)
Copy link
Member

Choose a reason for hiding this comment

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

Before being returned, this should be serialized (like https://github.com/edx/edx-exams/blob/d8cf60a98bd86be4cab31f16ae5969a7c52ef396/edx_exams/apps/api/v1/views.py#L227). This gives us better control over what we return.

- some docstring nits
- logic to ensure no index error w/ message_count in api
- serialize data before returning
Returns a number of messages equal to the message_count value.
"""
# If the received message count exceeds the number of messages present, we return all the messages queried.
actual_message_count = LearningAssistantMessage.objects.count()
Copy link
Member

Choose a reason for hiding this comment

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

I actually don't know if this is strictly necessary. Have you tested the code without this, and just indexing using the message_count value? Only asking because the same syntax is used here: https://github.com/openedx/edx-platform/blob/b20498cc4eec4ed1b85508967bef6c915372dd5b/openedx/core/djangoapps/notifications/tasks.py#L105

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh that actually works. I'll get rid of this code.

authentication_classes = (SessionAuthentication, JwtAuthentication,)
permission_classes = (IsAuthenticated,)

def get(self, request, course_run_id, message_count=50):
Copy link
Member

Choose a reason for hiding this comment

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

I still think this should be a query parameter, not a path parameter.

Copy link
Member Author

Choose a reason for hiding this comment

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

I keep mixing these up- I think I've got it right now, gonna use `request.GET.get('message_count', 50) instead.

Side note, what do you think the default value should be? Is 50 good?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that should be the right syntax! And 50 seems good.

@patch('learning_assistant.views.CourseMode')
@patch('learning_assistant.views.get_course_id')
def test_learning_message_history_view_get(self,
mock_get_course_id,
Copy link
Member

Choose a reason for hiding this comment

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

NIT: This spacing looks a little strange to me, can you remove the indents?

Copy link
Member Author

Choose a reason for hiding this comment

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

this was throwing a "line too long" quality error, I might just ignore it instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, I a better way by just moving the "self" param to the next line, then moving the spacing of all the params back to one tab past the function declaration.

Copy link
Member

Choose a reason for hiding this comment

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

You can also keep them on the same line, they don't each need to be on their own!

@@ -19,4 +19,9 @@
LearningAssistantEnabledView.as_view(),
name='enabled',
),
re_path(
fr'learning_assistant/v1/course_id/{COURSE_ID_PATTERN}/history/<int:message_count>',
Copy link
Member

Choose a reason for hiding this comment

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

the message count shouldn't be specified in the path, in my opinion. Happy to be convinced otherwise, but it feels more appropriate, as the message count param is used to filter on the resource being specified.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just realizing query parameters don't need to be in the URL... I'll get rid of that now

Copy link
Member

@schenedx schenedx left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Member

@alangsto alangsto left a comment

Choose a reason for hiding this comment

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

A few nits but otherwise looks good!


Accepts: [GET]

Path: /learning_assistant/v1/course_id/{course_key}/history/{message_count}
Copy link
Member

Choose a reason for hiding this comment

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

NIT: Could you update the path to reflect that message_count is no longer a path parameter?

)

# If user does not have an enrollment record, or is not staff, they should not have access
# NOTE: This will likely be removed once work is done to allow audit learners to access xpert
Copy link
Member

Choose a reason for hiding this comment

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

NIT: Should this note be left here?

@alangsto
Copy link
Member

Forgot one other NIT, but could you add an entry to the changelog for this? Thank you!

@ilee2u ilee2u merged commit ecfb6e8 into main Oct 31, 2024
4 checks passed
@ilee2u ilee2u deleted the ilee2u/get-message-history branch October 31, 2024 15:18
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.

4 participants