diff --git a/lms/djangoapps/learner_dashboard/programs.py b/lms/djangoapps/learner_dashboard/programs.py index 4d9e46f54b..7121cbaf37 100644 --- a/lms/djangoapps/learner_dashboard/programs.py +++ b/lms/djangoapps/learner_dashboard/programs.py @@ -5,6 +5,7 @@ Fragments for rendering programs. import json +from django.contrib.sites.shortcuts import get_current_site from django.http import Http404 from django.template.loader import render_to_string from django.urls import reverse @@ -13,9 +14,11 @@ from web_fragments.fragment import Fragment from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.learner_dashboard.utils import FAKE_COURSE_KEY, strip_course_id, program_discussions_is_enabled +from lti_consumer.lti_1p1.contrib.django import lti_embed from openedx.core.djangoapps.catalog.constants import PathwayType from openedx.core.djangoapps.catalog.utils import get_pathways from openedx.core.djangoapps.credentials.utils import get_credentials_records_url +from openedx.core.djangoapps.discussions.models import ProgramDiscussionsConfiguration from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.programs.utils import ( @@ -25,6 +28,7 @@ from openedx.core.djangoapps.programs.utils import ( get_program_marketing_url ) from openedx.core.djangoapps.user_api.preferences.api import get_user_preferences +from openedx.core.djangolib.markup import HTML class ProgramsFragmentView(EdxFragmentView): @@ -70,14 +74,93 @@ class ProgramDetailsFragmentView(EdxFragmentView): """ Render the program details fragment. """ + DEFAULT_ROLE = 'student' + + @staticmethod + def get_program_discussion_configuration(program_uuid): + return ProgramDiscussionsConfiguration.objects.filter( + program_uuid=program_uuid + ).first() + + @staticmethod + def _get_resource_link_id(program_uuid, request) -> str: + site = get_current_site(request) + return f'{site.domain}-{program_uuid}' + + @staticmethod + def _get_result_sourcedid(context_id, resource_link_id, user_id) -> str: + return f'{context_id}:{resource_link_id}:{user_id}' + + def _get_lti_embed_code(self, program_discussions_configuration, request) -> str: + """ + Returns the LTI embed code for embedding in the program discussions tab + Args: + program_discussions_configuration (ProgramDiscussionsConfiguration): ProgramDiscussionsConfiguration object. + request (HttpRequest): Request object for view in which LTI will be embedded. + Returns: + HTML code to embed LTI in program page. + """ + program_uuid = program_discussions_configuration.program_uuid + lti_consumer = program_discussions_configuration.lti_configuration.get_lti_consumer() + user_id = str(request.user.id) + context_id = program_uuid + resource_link_id = self._get_resource_link_id(program_uuid, request) + # TODO: Add support for multiple roles + roles = self.DEFAULT_ROLE + context_title = program_uuid + result_sourcedid = self._get_result_sourcedid(context_id, resource_link_id, user_id) + + return lti_embed( + html_element_id='lti-tab-launcher', + lti_consumer=lti_consumer, + resource_link_id=resource_link_id, + user_id=user_id, + roles=roles, + context_id=context_id, + context_title=context_title, + context_label=context_id, + result_sourcedid=result_sourcedid + ) + + def render_discussions_fragment(self, program_uuid, request) -> dict: + """ + Returns the program discussion fragment if program discussions configuration exists for a program uuid + """ + if program_discussions_is_enabled(): + program_discussions_configuration = self.get_program_discussion_configuration(program_uuid) + if program_discussions_configuration: + lti_embed_html = self._get_lti_embed_code(program_discussions_configuration, request) + fragment = Fragment( + HTML( + """ + + """ + ).format( + srcdoc=lti_embed_html + ) + ) + return { + 'iframe': fragment.content, + 'enabled': True + } + return { + 'iframe': '', + 'enabled': False + } def render_to_fragment(self, request, program_uuid, **kwargs): # lint-amnesty, pylint: disable=arguments-differ """View details about a specific program.""" programs_config = kwargs.get('programs_config') or ProgramsApiConfig.current() + user = request.user if not programs_config.enabled or not request.user.is_authenticated: raise Http404 - meter = ProgramProgressMeter(request.site, request.user, uuid=program_uuid) + meter = ProgramProgressMeter(request.site, user, uuid=program_uuid) program_data = meter.programs[0] if not program_data: @@ -88,9 +171,9 @@ class ProgramDetailsFragmentView(EdxFragmentView): except ValueError: mobile_only = False - program_data = ProgramDataExtender(program_data, request.user, mobile_only=mobile_only).extend() + program_data = ProgramDataExtender(program_data, user, mobile_only=mobile_only).extend() course_data = meter.progress(programs=[program_data], count_only=False)[0] - certificate_data = get_certificates(request.user, program_data) + certificate_data = get_certificates(user, program_data) program_data.pop('courses') skus = program_data.get('skus') @@ -130,13 +213,14 @@ class ProgramDetailsFragmentView(EdxFragmentView): context = { 'urls': urls, - 'user_preferences': get_user_preferences(request.user), + 'user_preferences': get_user_preferences(user), 'program_data': program_data, 'course_data': course_data, 'certificate_data': certificate_data, 'industry_pathways': industry_pathways, 'credit_pathways': credit_pathways, - 'program_discussions_enabled': program_discussions_is_enabled() + 'program_discussions_enabled': program_discussions_is_enabled(), + 'discussion_fragment': self.render_discussions_fragment(program_uuid, request) } html = render_to_string('learner_dashboard/program_details_fragment.html', context) diff --git a/lms/static/js/learner_dashboard/views/program_details_view.js b/lms/static/js/learner_dashboard/views/program_details_view.js index 9164c31074..996942acbb 100644 --- a/lms/static/js/learner_dashboard/views/program_details_view.js +++ b/lms/static/js/learner_dashboard/views/program_details_view.js @@ -80,8 +80,9 @@ class ProgramDetailsView extends Backbone.View { completedCount, completeProgramURL: buyButtonUrl, programDiscussionEnabled: this.options.programDiscussionEnabled, - industryPathways : this.options.industryPathways, - creditPathways : this.options.creditPathways, + industryPathways: this.options.industryPathways, + creditPathways: this.options.creditPathways, + discussionFragment: this.options.discussionFragment, }; data = $.extend(data, this.programModel.toJSON()); HtmlUtils.setHtml(this.$el, this.tpl(data)); diff --git a/lms/templates/learner_dashboard/program_details_fragment.html b/lms/templates/learner_dashboard/program_details_fragment.html index 015f01c9a7..018a237f55 100644 --- a/lms/templates/learner_dashboard/program_details_fragment.html +++ b/lms/templates/learner_dashboard/program_details_fragment.html @@ -21,6 +21,7 @@ ProgramDetailsFactory({ industryPathways: ${industry_pathways | n, dump_js_escaped_json}, creditPathways: ${credit_pathways | n, dump_js_escaped_json}, programDiscussionEnabled: ${program_discussions_enabled | n, dump_js_escaped_json}, + discussionFragment: ${discussion_fragment, | n, dump_js_escaped_json} }); diff --git a/lms/templates/learner_dashboard/program_details_tab_view.underscore b/lms/templates/learner_dashboard/program_details_tab_view.underscore index 76a1c3e02c..890e2d4454 100644 --- a/lms/templates/learner_dashboard/program_details_tab_view.underscore +++ b/lms/templates/learner_dashboard/program_details_tab_view.underscore @@ -7,7 +7,7 @@ - <% if (programDiscussionEnabled) { %> + <% if (discussionFragment.enabled) { %> @@ -101,9 +101,9 @@ - <% if (programDiscussionEnabled) { %> -
Community tab content
- <% } %> + <% if (discussionFragment.enabled) { %> +
<%= HtmlUtils.HTML(discussionFragment.iframe) %>
+ <% } %>
Live tab content
<% if (creditPathways.length > 0) { %> diff --git a/lms/templates/learner_dashboard/program_details_view.underscore b/lms/templates/learner_dashboard/program_details_view.underscore index d4ea908435..5216c1ef55 100644 --- a/lms/templates/learner_dashboard/program_details_view.underscore +++ b/lms/templates/learner_dashboard/program_details_view.underscore @@ -1,5 +1,6 @@
+
<% if (completedCount === totalCount) { %>