def include_theme_files(self, fragment): """ Gets theme configuration and renders theme css into fragment """ theme = self.get_theme() if not theme or 'package' not in theme: return theme_package, theme_files = theme.get('package', None), theme.get('locations', []) resource_loader = ResourceLoader(theme_package) for theme_file in theme_files: fragment.add_css(resource_loader.load_unicode(theme_file))
def student_view(self, context): """ XBlock student view of this component. Makes a request to `lti_launch_handler` either in an iframe or in a new window depending on the configuration of the instance of this XBlock Arguments: context (dict): XBlock context Returns: xblock.fragment.Fragment: XBlock HTML fragment """ fragment = Fragment() loader = ResourceLoader(__name__) context.update(self._get_context_for_template()) fragment.add_content(loader.render_mako_template('/templates/html/student.html', context)) fragment.add_css(loader.load_unicode('static/css/student.css')) fragment.add_javascript(loader.load_unicode('static/js/xblock_lti_consumer.js')) fragment.initialize_js('LtiConsumerXBlock') return fragment
def student_view(self, context): """ XBlock student view of this component. Arguments: context (dict): XBlock context Returns: xblock.fragment.Fragment: XBlock HTML fragment """ fragment = Fragment() loader = ResourceLoader(__name__) context.update(self._get_context_for_template()) fragment.add_content(loader.render_mako_template('/templates/player.html', context)) ''' Note: DO NOT USE the "latest" folder in production, but specify a version from https://aka.ms/ampchangelog . This allows us to run a test pass prior to ingesting later versions. ''' fragment.add_javascript(loader.load_unicode('node_modules/videojs-vtt.js/lib/vttcue.js')) fragment.add_css_url('//amp.azure.net/libs/amp/1.8.1/skins/amp-default/azuremediaplayer.min.css') fragment.add_javascript_url('//amp.azure.net/libs/amp/1.8.1/azuremediaplayer.min.js') fragment.add_javascript(loader.load_unicode('static/js/player.js')) fragment.add_css(loader.load_unicode('public/css/player.css')) # NOTE: The Azure Media Player JS file includes the VTT JavaScript library, so we don't # actually need to include our local copy of public/js/vendor/vtt.js. In fact, if we do # the overlay subtitles stop working # @TODO: Make sure all fields are well structured/formatted, if it is not correct, then # print out an error msg in view rather than just silently failing fragment.initialize_js('AzureMediaServicesBlock') return fragment
def handle_request(self, request): """ Handler for Outcome Service requests. Parses and validates XML request body. Currently, only the replaceResultRequest action is supported. Example of request body from LTI provider:: <?xml version = "1.0" encoding = "UTF-8"?> <imsx_POXEnvelopeRequest xmlns = "some_link (may be not required)"> <imsx_POXHeader> <imsx_POXRequestHeaderInfo> <imsx_version>V1.0</imsx_version> <imsx_messageIdentifier>528243ba5241b</imsx_messageIdentifier> </imsx_POXRequestHeaderInfo> </imsx_POXHeader> <imsx_POXBody> <replaceResultRequest> <resultRecord> <sourcedGUID> <sourcedId>feb-123-456-2929::28883</sourcedId> </sourcedGUID> <result> <resultScore> <language>en-us</language> <textString>0.4</textString> </resultScore> </result> </resultRecord> </replaceResultRequest> </imsx_POXBody> </imsx_POXEnvelopeRequest> See /templates/xml/outcome_service_response.xml for the response body format. Arguments: request (xblock.django.request.DjangoWebobRequest): Request object for current HTTP request Returns: str: Outcome Service XML response """ resource_loader = ResourceLoader(__name__) response_xml_template = resource_loader.load_unicode( '/templates/xml/outcome_service_response.xml') # Returns when `action` is unsupported. # Supported actions: # - replaceResultRequest. unsupported_values = { 'imsx_codeMajor': 'unsupported', 'imsx_description': 'Target does not support the requested operation.', 'imsx_messageIdentifier': 'unknown', 'response': '' } # Returns if: # - past due grades are not accepted and grade is past due # - score is out of range # - can't parse response from TP; # - can't verify OAuth signing or OAuth signing is incorrect. failure_values = { 'imsx_codeMajor': 'failure', 'imsx_description': 'The request has failed.', 'imsx_messageIdentifier': 'unknown', 'response': '' } request_body = request.body.decode('utf-8') if not self.xblock.accept_grades_past_due and self.xblock.is_past_due( ): failure_values['imsx_description'] = "Grade is past due" return response_xml_template.format(**failure_values) try: imsx_message_identifier, sourced_id, score, action = parse_grade_xml_body( request_body) except LtiError as ex: # pylint: disable=no-member body = escape(request_body) if request_body else '' error_message = "Request body XML parsing error: {} {}".format( str(ex), body) log.debug("[LTI]: %s", error_message) failure_values['imsx_description'] = error_message return response_xml_template.format(**failure_values) # Verify OAuth signing. __, secret = self.xblock.lti_provider_key_secret try: verify_oauth_body_signature(request, secret, self.xblock.outcome_service_url) except (ValueError, LtiError) as ex: failure_values['imsx_messageIdentifier'] = escape( imsx_message_identifier) error_message = "OAuth verification error: " + escape(str(ex)) failure_values['imsx_description'] = error_message log.debug("[LTI]: %s", error_message) return response_xml_template.format(**failure_values) real_user = self.xblock.runtime.get_real_user( urllib.parse.unquote(sourced_id.split(':')[-1])) if not real_user: # that means we can't save to database, as we do not have real user id. failure_values['imsx_messageIdentifier'] = escape( imsx_message_identifier) failure_values['imsx_description'] = "User not found." return response_xml_template.format(**failure_values) if action == 'replaceResultRequest': self.xblock.set_user_module_score(real_user, score, self.xblock.max_score()) values = { 'imsx_codeMajor': 'success', 'imsx_description': 'Score for {sourced_id} is now {score}'.format( sourced_id=sourced_id, score=score), 'imsx_messageIdentifier': escape(imsx_message_identifier), 'response': '<replaceResultResponse/>' } log.debug(u"[LTI]: Grade is saved.") return response_xml_template.format(**values) unsupported_values['imsx_messageIdentifier'] = escape( imsx_message_identifier) log.debug(u"[LTI]: Incorrect action.") return response_xml_template.format(**unsupported_values)
def student_view(self, context=None): """ The primary view of the StaffGradedXBlock, shown to students when viewing courses. """ frag = Fragment() frag.add_css(self.resource_string("static/css/staff_graded.css")) loader = ResourceLoader(__name__) _ = self.runtime.service(self, "i18n").ugettext # Add i18n js statici18n_js_url = self._get_statici18n_js_url() if statici18n_js_url: frag.add_javascript_url( self.runtime.local_resource_url(self, statici18n_js_url)) frag.add_javascript( self.resource_string("static/js/src/staff_graded.js")) frag.initialize_js('StaffGradedXBlock') context['id'] = self.location.html_id() context['instructions'] = markdown.markdown(self.instructions) context['display_name'] = self.display_name context['is_staff'] = self.runtime.user_is_staff course_id = self.location.course_key context['available_cohorts'] = [ cohort.name for cohort in get_course_cohorts(course_id=course_id) ] context['available_tracks'] = [ (mode.slug, mode.name) for mode in modes_for_course(course_id, only_selectable=False) ] if context['is_staff']: from crum import get_current_request from django.middleware.csrf import get_token context['import_url'] = self.runtime.handler_url( self, "csv_import_handler") context['export_url'] = self.runtime.handler_url( self, "csv_export_handler") context['poll_url'] = self.runtime.handler_url( self, "get_results_handler") context['csrf_token'] = get_token(get_current_request()) frag.add_javascript( loader.load_unicode('static/js/src/staff_graded.js')) frag.initialize_js('StaffGradedProblem', json_args={ k: context[k] for k in ('csrf_token', 'import_url', 'export_url', 'poll_url', 'id') }) try: score = get_score(self.location, self.runtime.user_id) or {} context['grades_available'] = True except NoSuchServiceError: context['grades_available'] = False else: if score: grade = score['score'] context['score_string'] = _('{score} / {total} points').format( score=grade, total=self.weight) else: context['score_string'] = _('{total} points possible').format( total=self.weight) frag.add_content( loader.render_django_template('static/html/staff_graded.html', context)) return frag
def handle_request(self, request): """ Handler for Outcome Service requests. Parses and validates XML request body. Currently, only the replaceResultRequest action is supported. Example of request body from LTI provider:: <?xml version = "1.0" encoding = "UTF-8"?> <imsx_POXEnvelopeRequest xmlns = "some_link (may be not required)"> <imsx_POXHeader> <imsx_POXRequestHeaderInfo> <imsx_version>V1.0</imsx_version> <imsx_messageIdentifier>528243ba5241b</imsx_messageIdentifier> </imsx_POXRequestHeaderInfo> </imsx_POXHeader> <imsx_POXBody> <replaceResultRequest> <resultRecord> <sourcedGUID> <sourcedId>feb-123-456-2929::28883</sourcedId> </sourcedGUID> <result> <resultScore> <language>en-us</language> <textString>0.4</textString> </resultScore> </result> </resultRecord> </replaceResultRequest> </imsx_POXBody> </imsx_POXEnvelopeRequest> See /templates/xml/outcome_service_response.xml for the response body format. Arguments: request (xblock.django.request.DjangoWebobRequest): Request object for current HTTP request Returns: str: Outcome Service XML response """ resource_loader = ResourceLoader(__name__) response_xml_template = resource_loader.load_unicode('/templates/xml/outcome_service_response.xml') # Returns when `action` is unsupported. # Supported actions: # - replaceResultRequest. unsupported_values = { 'imsx_codeMajor': 'unsupported', 'imsx_description': 'Target does not support the requested operation.', 'imsx_messageIdentifier': 'unknown', 'response': '' } # Returns if: # - past due grades are not accepted and grade is past due # - score is out of range # - can't parse response from TP; # - can't verify OAuth signing or OAuth signing is incorrect. failure_values = { 'imsx_codeMajor': 'failure', 'imsx_description': 'The request has failed.', 'imsx_messageIdentifier': 'unknown', 'response': '' } if not self.xblock.accept_grades_past_due and self.xblock.is_past_due: failure_values['imsx_description'] = "Grade is past due" return response_xml_template.format(**failure_values) try: imsx_message_identifier, sourced_id, score, action = parse_grade_xml_body(request.body) except LtiError as ex: # pylint: disable=no-member body = escape(request.body) if request.body else '' error_message = "Request body XML parsing error: {} {}".format(ex.message, body) log.debug("[LTI]: %s" + error_message) failure_values['imsx_description'] = error_message return response_xml_template.format(**failure_values) # Verify OAuth signing. __, secret = self.xblock.lti_provider_key_secret try: verify_oauth_body_signature(request, secret, self.xblock.outcome_service_url) except (ValueError, LtiError) as ex: failure_values['imsx_messageIdentifier'] = escape(imsx_message_identifier) error_message = "OAuth verification error: " + escape(ex.message) failure_values['imsx_description'] = error_message log.debug("[LTI]: " + error_message) return response_xml_template.format(**failure_values) real_user = self.xblock.runtime.get_real_user(urllib.unquote(sourced_id.split(':')[-1])) if not real_user: # that means we can't save to database, as we do not have real user id. failure_values['imsx_messageIdentifier'] = escape(imsx_message_identifier) failure_values['imsx_description'] = "User not found." return response_xml_template.format(**failure_values) if action == 'replaceResultRequest': self.xblock.set_user_module_score(real_user, score, self.xblock.max_score()) values = { 'imsx_codeMajor': 'success', 'imsx_description': 'Score for {sourced_id} is now {score}'.format(sourced_id=sourced_id, score=score), 'imsx_messageIdentifier': escape(imsx_message_identifier), 'response': '<replaceResultResponse/>' } log.debug("[LTI]: Grade is saved.") return response_xml_template.format(**values) unsupported_values['imsx_messageIdentifier'] = escape(imsx_message_identifier) log.debug("[LTI]: Incorrect action.") return response_xml_template.format(**unsupported_values)