Skip to content
Draft
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
22 changes: 19 additions & 3 deletions lms/djangoapps/edxnotes/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ def get_html(self, *args, **kwargs):
Returns raw html for the component.
"""
# Import is placed here to avoid model import at project startup.
from .helpers import generate_uid, get_edxnotes_id_token, get_public_endpoint, get_token_url, is_feature_enabled
from .helpers import (
generate_uid,
get_ccx_master_course_key,
get_ccx_master_usage_key,
get_edxnotes_id_token,
get_public_endpoint,
get_token_url,
is_feature_enabled,
)

if not settings.ENABLE_EDXNOTES:
return original_get_html(self, *args, **kwargs)
Expand All @@ -47,6 +55,14 @@ def get_html(self, *args, **kwargs):
if is_studio or not is_feature_enabled(course, user):
return original_get_html(self, *args, **kwargs)
else:
# Notes are recorded against the master course (and its own block ids),
# not the CCX, so a note taken in any CCX section shows up in every CCX
# section derived from the same master course. `tokenUrl` deliberately
# keeps the real (CCX) course id: that URL is routed/access-checked
# against the course actually being viewed, not the note's data key.
notes_course_id = get_ccx_master_course_key(course.id)
notes_usage_id = get_ccx_master_usage_key(self.scope_ids.usage_id)

return render_to_string("edxnotes_wrapper.html", {
"content": original_get_html(self, *args, **kwargs),
"uid": generate_uid(),
Expand All @@ -55,8 +71,8 @@ def get_html(self, *args, **kwargs):
),
"params": {
# Use camelCase to name keys.
"usageId": self.scope_ids.usage_id,
"courseId": course.id,
"usageId": notes_usage_id,
"courseId": notes_course_id,
"token": get_edxnotes_id_token(user),
"tokenUrl": get_token_url(course.id),
"endpoint": get_public_endpoint(),
Expand Down
36 changes: 35 additions & 1 deletion lms/djangoapps/edxnotes/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,37 @@ def get_token_url(course_id):
})


def get_ccx_master_course_key(course_key):
"""
If `course_key` identifies a CCX (Custom Course for edX), return the CourseKey
of the CCX's master course. Otherwise return `course_key` unchanged.

This lets notes/annotations created while viewing a CCX be recorded against the
shared master course rather than that one CCX section, so the same user sees the
same notes on every CCX section (and the master course itself) derived from it.
"""
ccx_id = getattr(course_key, 'ccx', None)
if not ccx_id:
return course_key

# Imported locally to avoid a hard import-time dependency between the edxnotes
# and ccx apps.
from lms.djangoapps.ccx.utils import get_ccx_from_ccx_locator # pylint: disable=import-outside-toplevel
ccx = get_ccx_from_ccx_locator(course_key)
return ccx.course_id if ccx else course_key


def get_ccx_master_usage_key(usage_key):
"""
If `usage_key` identifies a block within a CCX, return the equivalent UsageKey
for the same block within the CCX's master course (CCX field overrides and
scheduling don't change the underlying content, so the block ids line up).
Otherwise return `usage_key` unchanged.
"""
to_block_locator = getattr(usage_key, 'to_block_locator', None)
return to_block_locator() if to_block_locator else usage_key


def send_request(user, course_id, page, page_size, path="", text=None):
"""
Sends a request to notes api with appropriate parameters and headers.
Expand Down Expand Up @@ -332,7 +363,10 @@ def get_notes(request, course, page=DEFAULT_PAGE, page_size=DEFAULT_PAGE_SIZE, t
results: list with notes info dictionary. each item in this list will be a dict
"""
path = 'search' if text else 'annotations'
response = send_request(request.user, course.id, page, page_size, path, text)
# Resolve to the master course so notes taken inside any CCX section are
# recorded against (and read back from) the shared master course.
notes_course_id = get_ccx_master_course_key(course.id)
response = send_request(request.user, notes_course_id, page, page_size, path, text)

try:
collection = json.loads(response.content.decode('utf-8'))
Expand Down