예제 #1
0
 def student_view(self, context):
     return Fragment()
예제 #2
0
    def student_view(self, context=None):
        """
        The primary view of the RecapXBlock seen in LMS
        """
        blocks = []
        for usage_key, xblock_type in self.get_blocks(self.xblock_list):
            block = self.runtime.get_block(usage_key)

            if hasattr(block, 'custom_report_format'):
                question = str(block.display_name)

                try:
                    user = self.runtime.get_real_user(self.runtime.anonymous_student_id)
                except TypeError:
                    user = None

                answer = block.custom_report_format(
                    user=user,
                    block=block,
                )

                blocks.append((question, answer))
            elif xblock_type == 'problem':
                answer = u""
                question = u""
                try:
                    question = str(block.display_name)
                    answer = self.get_submission(usage_key)
                    if answer is None:
                        answer = block.lcp.get_question_answer_text()
                    blocks.append((question, answer))
                except Exception as e:
                    logger.warn(str(e))
                    answer = block.lcp.get_question_answer_text()
                    blocks.append((question, answer))

        layout = self.get_user_layout(blocks)

        idArray = self.scope_ids.usage_id._to_string().split('@')
        xblockId = idArray[len(idArray) - 1]
        context = {
            'recap_answers_id': 'recap_answers_' + xblockId,
            'recap_editor_id': 'recap_editor_' + xblockId,
            'recap_cmd_id': 'recap_cmd_' + xblockId,
            'blocks': blocks,
            'layout': layout,
            'allow_download': self.allow_download,
            'download_text': self.download_text,
        }

        frag = Fragment(
            loader.render_django_template(
                "static/html/recap.html",
                context).format(self=self)
        )
        if (self.css_file):
            frag.add_css(self.css_file)

        frag.add_css(self.resource_string("static/css/recap.css"))
        frag.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/FileSaver.js/FileSaver.min.js'
            )
        )
        frag.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/jspdf.min.js'
            )
        )

        frag.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/html2canvas.min.js'
            )
        )
        frag.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/html2pdf.js'
            )
        )

        frag.add_javascript(self.resource_string("static/js/src/recap.js"))
        frag.initialize_js('RecapXBlock', {
            'recap_answers_id': 'recap_answers_' + xblockId,
            'recap_editor_id': 'recap_editor_' + xblockId,
            'recap_cmd_id': 'recap_cmd_' + xblockId,
        })

        return frag
예제 #3
0
 def student_view_aside(self, block, context):  # pylint: disable=unused-argument
     """Add to the student view"""
     return Fragment(self.FRAG_CONTENT)
예제 #4
0
 def fallback_view(self, view_name, context=None):  # pylint: disable=W0613
     """Provide a fallback view handler"""
     return Fragment(u"Hello, World!")
예제 #5
0
    def student_view(self, context):
        if self.child is None:
            # raise error instead?  In fact, could complain on descriptor load...
            return Fragment(content=u"<div>Nothing to randomize between</div>")

        return self.child.render(STUDENT_VIEW, context)
예제 #6
0
def xblock_view_handler(request, usage_key_string, view_name):
    """
    The restful handler for requests for rendered xblock views.

    Returns a json object containing two keys:
        html: The rendered html of the view
        resources: A list of tuples where the first element is the resource hash, and
            the second is the resource description
    """
    usage_key = usage_key_with_run(usage_key_string)
    if not has_studio_read_access(request.user, usage_key.course_key):
        raise PermissionDenied()

    accept_header = request.META.get('HTTP_ACCEPT', 'application/json')

    if 'application/json' in accept_header:
        store = modulestore()
        xblock = store.get_item(usage_key)
        container_views = [
            'container_preview', 'reorderable_container_child_preview',
            'container_child_preview'
        ]

        # wrap the generated fragment in the xmodule_editor div so that the javascript
        # can bind to it correctly
        xblock.runtime.wrappers.append(
            partial(
                wrap_xblock,
                'StudioRuntime',
                usage_id_serializer=unicode,
                request_token=request_token(request),
            ))

        if view_name in (STUDIO_VIEW, VISIBILITY_VIEW):
            try:
                fragment = xblock.render(view_name)
            # catch exceptions indiscriminately, since after this point they escape the
            # dungeon and surface as uneditable, unsaveable, and undeletable
            # component-goblins.
            except Exception as exc:  # pylint: disable=broad-except
                log.debug("Unable to render %s for %r",
                          view_name,
                          xblock,
                          exc_info=True)
                fragment = Fragment(
                    render_to_string('html_error.html', {'message': str(exc)}))

        elif view_name in (PREVIEW_VIEWS + container_views):
            is_pages_view = view_name == STUDENT_VIEW  # Only the "Pages" view uses student view in Studio
            can_edit = has_studio_write_access(request.user,
                                               usage_key.course_key)

            # Determine the items to be shown as reorderable. Note that the view
            # 'reorderable_container_child_preview' is only rendered for xblocks that
            # are being shown in a reorderable container, so the xblock is automatically
            # added to the list.
            reorderable_items = set()
            if view_name == 'reorderable_container_child_preview':
                reorderable_items.add(xblock.location)

            paging = None
            try:
                if request.REQUEST.get('enable_paging', 'false') == 'true':
                    paging = {
                        'page_number':
                        int(request.REQUEST.get('page_number', 0)),
                        'page_size': int(request.REQUEST.get('page_size', 0)),
                    }
            except ValueError:
                # pylint: disable=too-many-format-args
                return HttpResponse(
                    content="Couldn't parse paging parameters: enable_paging: "
                    "%s, page_number: %s, page_size: %s".format(
                        request.REQUEST.get('enable_paging', 'false'),
                        request.REQUEST.get('page_number', 0),
                        request.REQUEST.get('page_size', 0)),
                    status=400,
                    content_type="text/plain",
                )

            # Set up the context to be passed to each XBlock's render method.
            context = {
                'is_pages_view':
                is_pages_view,  # This setting disables the recursive wrapping of xblocks
                'is_unit_page': is_unit(xblock),
                'can_edit': can_edit,
                'root_xblock': xblock if
                (view_name == 'container_preview') else None,
                'reorderable_items': reorderable_items,
                'paging': paging,
            }

            fragment = get_preview_fragment(request, xblock, context)

            # Note that the container view recursively adds headers into the preview fragment,
            # so only the "Pages" view requires that this extra wrapper be included.
            if is_pages_view:
                fragment.content = render_to_string(
                    'component.html', {
                        'xblock_context':
                        context,
                        'xblock':
                        xblock,
                        'locator':
                        usage_key,
                        'preview':
                        fragment.content,
                        'label':
                        xblock.display_name or xblock.scope_ids.block_type,
                    })
        else:
            raise Http404

        hashed_resources = OrderedDict()
        for resource in fragment.resources:
            hashed_resources[hash_resource(resource)] = resource

        return JsonResponse({
            'html': fragment.content,
            'resources': hashed_resources.items()
        })

    else:
        return HttpResponse(status=406)
예제 #7
0
    def student_view(self, _context=None):  # pylint: disable=unused-argument
        """
        The primary view of the RecommenderXBlock, shown to students
        when viewing courses.
        """
        self.recommendations = (data_structure_upgrade(self.recommendations)
                                or data_structure_upgrade(
                                    self.default_recommendations) or {})

        # Transition between two versions. In the previous version, there is
        # no endorsed_recommendation_reasons. Thus, we add empty reasons to
        # make the length of the two lists equal
        #
        # TODO: Go through old lists of resources in course, and remove this
        # code. The migration should be done.
        while len(self.endorsed_recommendation_ids) > len(
                self.endorsed_recommendation_reasons):
            self.endorsed_recommendation_reasons.append('')

        global template_lookup
        if not template_lookup:
            self._init_template_lookup()

        # Ideally, we'd estimate score based on votes, such that items with
        # 1 vote have a sensible ranking (rather than a perfect rating)

        # We pre-generate URLs for all resources. We benchmarked doing this
        # for 44 URLs, and the time per URL was about 8ms. The 44 URLs were
        # all of the images added by students over several problem sets. If
        # load continues to be as-is, pre-generation is not a performance
        # issue. If students make substantially more resources, we may want
        # to paginate, and generate in sets of 5-20 URLs per load.
        resources = [{
            'id': r['id'],
            'title': r['title'],
            "votes": r['upvotes'] - r['downvotes'],
            'url': r['url'],
            'description': self._get_onetime_url(r['description']),
            'descriptionText': r['descriptionText']
        } for r in self.recommendations.values()]
        resources = sorted(resources, key=lambda r: r['votes'], reverse=True)

        frag = Fragment(
            template_lookup.get_template("recommender.html").render(
                resources=resources,
                upvoted_ids=self.upvoted_ids,
                downvoted_ids=self.downvoted_ids,
                endorsed_recommendation_ids=self.endorsed_recommendation_ids,
                endorsed_recommendation_reasons=self.
                endorsed_recommendation_reasons,
                flagged_ids=self.flagged_ids,
                flagged_reasons=self.flagged_reasons))
        frag.add_css_url(
            "//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css"
        )
        frag.add_javascript_url(
            "//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js")
        frag.add_javascript_url(
            '//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.8.1/mustache.min.js'
        )
        frag.add_javascript_url(
            '//cdnjs.cloudflare.com/ajax/libs/intro.js/0.5.0/intro.min.js')
        frag.add_css(self.resource_string("static/css/tooltipster.css"))
        frag.add_css(self.resource_string("static/css/recommender.css"))
        frag.add_css(self.resource_string("static/css/introjs.css"))
        frag.add_javascript(
            self.resource_string("static/js/src/jquery.tooltipster.min.js"))
        frag.add_javascript(self.resource_string("static/js/src/cats.js"))
        frag.add_javascript(
            self.resource_string("static/js/src/recommender.js"))
        frag.initialize_js('RecommenderXBlock',
                           self.get_client_configuration())
        return frag
예제 #8
0
    def student_view(self, context=None):
        """
        The primary view of the FeedbackXBlock, shown to students
        when viewing courses.
        """
        # Figure out which prompt we show. We set self.prompt_choice to
        # the index of the prompt. We set it if it is out of range (either
        # uninitiailized, or incorrect due to changing list length). Then,
        # we grab the prompt, prepopulated with defaults.
        if self.prompt_choice < 0 or self.prompt_choice >= len(self.prompts):
            self.prompt_choice = random.randint(0, len(self.prompts) - 1)
        prompt = self.get_prompt()

        # Now, we render the FeedbackXBlock.
        html = self.resource_string("static/html/feedback.html")

        # Staff see vote totals, so we have slightly different HTML here.
        if self.vote_aggregate and self.is_staff():
            scale_item = self.resource_string("static/html/staff_item.html")
        else:
            scale_item = self.resource_string("static/html/scale_item.html")
        # The replace allows us to format the HTML nicely without getting
        # extra whitespace
        scale_item = scale_item.replace('\n', '')

        # We have five Likert fields right now, but we'd like this to
        # be dynamic
        indexes = range(5)

        # If the user voted before, we'd like to show that
        active_vote = ["checked" if i == self.user_vote else ""
                       for i in indexes]

        # Confirm that we do have vote totals (this may be uninitialized
        # otherwise). This should probably go into __init__ or similar.
        self.init_vote_aggregate()
        votes = self.vote_aggregate

        # We grab the icons. This should move to a Filesystem field so
        # instructors can upload new ones
        def get_url(icon_type, i):
            '''
            Helper function to generate the URL for the icons shown in the
            tool. Takes the type of icon (active, inactive, etc.) and
            the number of the icon.

            Note that some icon types may not be actively used in the
            styling. For example, at the time of this writing, we do
            selected through CSS, rather than by using those icons.
            '''
            templates = {'inactive': 'public/default_icons/i{set}{i}.png',
                         'active': 'public/default_icons/a{set}{i}.png',
                         'selected': 'public/default_icons/s{set}{i}.png'}
            template = templates[icon_type]
            icon_file = template.format(i=i, set=prompt['icon_set'])
            return self.runtime.local_resource_url(self, icon_file)
        ina_urls = [get_url('inactive', i) for i in range(1, 6)]
        act_urls = [get_url('active', i) for i in range(1, 6)]
        sel_urls = [get_url('selected', i) for i in range(1, 6)]

        # Render the Likert scale (not the whole page)
        scale = u"".join(
            scale_item.format(scale_text=scale_text,
                              unicode_icon=unicode_icon,
                              idx=idx,
                              active=active,
                              vote_cnt=vote_cnt,
                              ina_icon=ina_icon,
                              act_icon=act_icon,
                              sel_icon=sel_icon) for
            (scale_text,
             unicode_icon,
             idx,
             active,
             vote_cnt,
             act_icon,
             ina_icon,
             sel_icon) in
            zip(prompt['scale_text'],
                ICON_SETS[(prompt['icon_set'])],
                indexes,
                active_vote,
                votes,
                act_urls,
                ina_urls,
                sel_urls)
        )
        if self.user_vote != -1:
            _ = self.runtime.service(self, 'i18n').ugettext
            response = _("Thank you for voting!")
        else:
            response = ""
        # Now, render the whole page
        rendered = html.format(self=self,
                               scale=scale,
                               freeform_prompt=prompt['freeform'],
                               likert_prompt=prompt['likert'],
                               response=response,
                               placeholder=prompt['placeholder'])

        # We initialize self.p_user if not initialized -- this sets whether
        # or not we show it. From there, if it is less than odds of showing,
        # we set the fragment to the rendered XBlock. Otherwise, we return
        # empty HTML. There ought to be a way to return None, but XBlocks
        # doesn't support that.
        if self.p_user == -1:
            self.p_user = random.uniform(0, 100)
        if self.p_user < self.p:
            frag = Fragment(rendered)
        else:
            frag = Fragment(u"")

        # Finally, we do the standard JS+CSS boilerplate. Honestly, XBlocks
        # ought to have a sane default here.
        frag.add_css(self.resource_string("static/css/feedback.css"))
        frag.add_javascript(self.resource_string("static/js/src/feedback.js"))
        frag.initialize_js('FeedbackXBlock')
        return frag
예제 #9
0
    def student_view(self, context=None):

        # runtime error
        if not hasattr(self.runtime, "anonymous_student_id"):
            return self.message_view(
                "Error in uc_docker (get anonymous student id)",
                "Cannot get anonymous_student_id in runtime", context)

        # preview in studio
        if self.runtime.anonymous_student_id == "student":

            result, message = GitLabUtil.get_user_projects(
                self.git_host, self.git_port, self.git_teacher_token)
            if not result:
                return self.message_view(
                    "Error in uc_docker (get git projects)",
                    "Cannot get user's projects in git", context)

            context_dict = {"labs": self.labs, "message": ""}
            fragment = Fragment()
            fragment.add_content(
                Util.render_template('static/html/uc_lab.html', context_dict))
            fragment.add_css(Util.load_resource("static/css/uc_docker.css"))
            fragment.add_javascript(
                Util.load_resource("static/js/src/uc_lab.js"))
            fragment.initialize_js("UcDockerXBlock")
            return fragment
            return

        # student view in open-edx
        if self.is_new:
            # create git account when first visiting
            student = self.runtime.get_real_user(
                self.runtime.anonymous_student_id)
            email = student.email
            name = student.first_name + " " + student.last_name
            username = student.username
            self.git_password = Util.create_random_password()
            self.save()
            # first_name, last_name are empty
            if name == " ":
                name = username
            self.logger.info("password is " + self.git_password)

            # create ldap account
            l = ldap.initialize(self.ldap_url)
            l.bind(self.principal_name, self.ldap_password)
            dn = "uid=" + username + "," + self.base_dn

            attrs = {}
            attrs['objectclass'] = ['top', 'inetOrgPerson', 'eduPerson']
            attrs['cn'] = str(username)
            attrs['sn'] = str(username)
            attrs['givenName'] = str(username)
            attrs['uid'] = str(username)
            attrs['userPassword'] = str(self.git_password)
            attrs['description'] = 'ldap user for shibboleth'
            attrs['eduPersonPrincipalName'] = str(email)
            attrs['mail'] = str(email)
            # Convert our dict to nice syntax for the add-function using modlist-module
            ldif = modlist.addModlist(attrs)
            l.add_s(dn, ldif)
            l.unbind_s()
            self.logger.info("create ldap account " + username + "," + dn)

            self.logger.info(self.git_host + "," + str(self.git_port) + "," +
                             self.git_admin_token + "," + name + "," +
                             username + "," + email + "," + self.git_password)
            result, message = GitLabUtil.create_account(
                self.git_host, self.git_port, self.git_admin_token, name,
                username, email, self.git_password)
            self.logger.info("create_account result:")
            self.logger.info(result)
            self.logger.info(message)
            if not result:
                return self.message_view(
                    "Error in uc_docker (create git account)", message,
                    context)

            result, message = GitLabUtil.login(self.git_host, self.git_port,
                                               username, self.git_password)
            self.logger.info("login result:")
            self.logger.info(result)
            self.logger.info(message)
            if not result:
                return self.message_view(
                    "Error in uc_docker (login git account)", message, context)

            try:
                message = json.loads(message)
                self.git_id = message["id"]
                self.git_user_token = message["private_token"]
                self.save()

            except Exception, ex:
                return self.message_view(
                    "Error in uc_docker (load json string)", message, context)

            try:
                self.private_key, self.public_key = Util.gen_ssh_keys(email)
                self.logger.info("private_key:" + self.private_key)
                self.save()
                conn = pymongo.Connection('localhost', 27017)
                db = conn.test
                db.authenticate(self.mongo_pwd, self.mongo_pwd)
                token = db.token
                token.insert({
                    "username": username,
                    "token": message["private_token"],
                    "password": self.git_password,
                    "private_key": self.private_key,
                    "public_key": self.public_key
                })
                conn.disconnect()

            except Exception, ex:
                return self.message_view("Error in uc_docker (gen ssh key)",
                                         ex, context)
예제 #10
0
 def get_frag(self, **context):  # pylint: disable=unused-argument
     """
     Return a Fragment required to render video player on the client side.
     """
     return Fragment(u'[Here be Video]')
예제 #11
0
    def student_view(self, context):
        """
        The primary view for the students
        """

        # Setup data to claim a badge
        self.n_user_id          = self.get_student_id()
        self.claim_db_user_data = self.DB_get_user_data()
        self.claim_db_user_id   = self.claim_db_user_data[0]
        self.claim_db_user_course = self.claim_db_user_data[1]
        self.claim_db_user_name = self.claim_db_user_data[2]
        self.claim_db_user_email = self.claim_db_user_data[3]
        self.claim_db_user_score = self.claim_db_user_data[4]
        self.claim_db_problems_lists = self.claim_db_user_data[5]
        self.claim_db_problems_total_score = self.claim_db_user_data[6]
        self.claim_db_problems_partial_score = self.claim_db_user_data[7]
        self.claim_db_problems_percent_score = self.claim_db_user_data[8]
        self.claim_db_badge_problems_score = self.claim_db_user_data[9]
        self.user_score = self.claim_db_user_data[4]
        claim_name = self.claim_db_user_name
        claim_mail = self.claim_db_user_email
        self.claim_badge_errors = self.claim_badge_errors
        self.claim_badge_form   = ''
        self.check_earned  = ''
        self.preview_badge = ''
        # Check out provider badge data
        if self.claim_badge_errors == "":
            self.claim_prov_access_token = self.iblclient.get_auth_token(self.claim_prov_usr, self.claim_prov_pwd)
            if self.claim_prov_access_token !="":
                badge_info = self.iblclient.get_badge_data(self.claim_prov_access_token,self.bg_id,'info')
                badge_params = self.iblclient.get_badge_data(self.claim_prov_access_token,self.bg_id,'params')
                obj_badge = self.iblclient.create_obj_badge(badge_info,badge_params)
                self.check_earned = self.iblclient.check_earn_badge(self.claim_prov_access_token,self.claim_db_user_email,self.bg_id)
                self.preview_badge = self.iblclient.build_badge_preview(obj_badge)
                if obj_badge :
                    # check if user has been awarded yet
                    if self.check_earned!='':
                        self.award_earn_prov = self.iblclient.get_award_result ( self.check_earned )
                        self.award_earned = self.iblclient.get_award_result_formatted(self.award_earn_prov,self.congratulations_text)
                    else:
                        self.claim_badge_form = self.iblclient.build_badge_form(self.claim_db_user_name,self.claim_db_user_email,self.form_text,obj_badge)
                else:
                    self.claim_badge_errors = 'Could not retrieve the information associated with the Badge ID selected. Please, verify your data.'
            else:
                self.claim_badge_errors = 'Could not connect to provider. Please, verify your credentials.'
        # Initialize html view
        self.claim_data = ""
        if self.claim_badge_errors == "":
            if self.debug_mode == "1":
                html = self.resource_string("static/html/debug.html")
            else:
                if int(self.user_score) < int(self.required_score):
                    html = self.resource_string("static/html/student_view_noscore.html")
                else:
                    if self.check_earned!='':
                        html = self.resource_string("static/html/student_view_earn_badge.html")
                    else:
                        html = self.resource_string("static/html/student_view_claim_badge.html")
            frag = Fragment(html.format(self=self))
            frag.add_css(self.resource_string("static/css/style.css"))
            if self.check_earned =='':
                frag.add_javascript(self.resource_string("static/js/src/student_view_scripts.js"))
            frag.initialize_js('StudentViewBadge')
        else:
            if self.debug_mode == "1":
                html = self.resource_string("static/html/result_errors_debug.html")
            else:
                html = self.resource_string("static/html/result_errors.html")
            frag = Fragment(html.format(self=self))
            frag.add_css(self.resource_string("static/css/style.css"))
        return frag
예제 #12
0
    def student_view(self, context):
        # If we're rendering this sequence, but no position is set yet,
        # default the position to the first element
        if self.position is None:
            self.position = 1

        ## Returns a set of all types of all sub-children
        contents = []

        fragment = Fragment()
        context = context or {}

        bookmarks_service = self.runtime.service(self, "bookmarks")
        context["username"] = self.runtime.service(
            self, "user").get_current_user().opt_attrs['edx-platform.username']

        display_names = [
            self.get_parent().display_name or '', self.display_name or ''
        ]
        # Is this sequential part of a timed or proctored exam?
        if self.is_time_limited:
            view_html = self._time_limited_student_view(context)

            # Do we have an alternate rendering
            # from the edx_proctoring subsystem?
            if view_html:
                fragment.add_content(view_html)
                return fragment

        for child in self.get_display_items():
            is_bookmarked = bookmarks_service.is_bookmarked(
                usage_key=child.scope_ids.usage_id)
            context["bookmarked"] = is_bookmarked

            progress = child.get_progress()
            rendered_child = child.render(STUDENT_VIEW, context)
            fragment.add_frag_resources(rendered_child)

            # `titles` is a list of titles to inject into the sequential tooltip display.
            # We omit any blank titles to avoid blank lines in the tooltip display.
            titles = [
                title.strip() for title in child.get_content_titles()
                if title.strip()
            ]
            childinfo = {
                'content': rendered_child.content,
                'title': "\n".join(titles),
                'page_title': titles[0] if titles else '',
                'progress_status': Progress.to_js_status_str(progress),
                'progress_detail': Progress.to_js_detail_str(progress),
                'type': child.get_icon_class(),
                'id': child.scope_ids.usage_id.to_deprecated_string(),
                'bookmarked': is_bookmarked,
                'path': " > ".join(display_names + [child.display_name or '']),
            }
            if childinfo['title'] == '':
                childinfo['title'] = child.display_name_with_default_escaped
            contents.append(childinfo)

        params = {
            'items': contents,
            'element_id': self.location.html_id(),
            'item_id': self.location.to_deprecated_string(),
            'position': self.position,
            'tag': self.location.category,
            'ajax_url': self.system.ajax_url,
        }

        fragment.add_content(
            self.system.render_template("seq_module.html", params))

        return fragment
예제 #13
0
    def student_view(self, context=None, authoring=False):
        scheme = 'https' if settings.HTTPS == 'on' else 'http'
        lms_base = settings.ENV_TOKENS.get('LMS_BASE')
        if isinstance(context, QueryDict):
            context = context.dict()

        if microsite.is_request_in_microsite():
            subdomain = microsite.get_value(
                "domain_prefix",
                None) or microsite.get_value('microsite_config_key')
            lms_base = "{}.{}".format(subdomain, lms_base)
        scorm_player_url = ""

        course_directory = self.scorm_file
        if self.scorm_player == 'SCORM_PKG_INTERNAL':
            # TODO: support initial filename other than index.html for internal players
            scorm_player_url = '{}://{}{}'.format(scheme, lms_base,
                                                  self.scorm_file)
        elif self.scorm_player:
            player_config = DEFINED_PLAYERS[self.scorm_player]
            player = player_config['location']
            if '://' in player:
                scorm_player_url = player
            else:
                scorm_player_url = '{}://{}{}'.format(scheme, lms_base, player)
            course_directory = '{}://{}{}'.format(
                scheme, lms_base,
                self.runtime.handler_url(self, "proxy_content"))

        html = self.resource_string("static/html/scormxblock.html")

        # don't call handlers if student_view is not called from within LMS
        # (not really a student)
        if not authoring:
            get_url = '{}://{}{}'.format(
                scheme, lms_base,
                self.runtime.handler_url(self, "get_raw_scorm_status"))
            set_url = '{}://{}{}'.format(
                scheme, lms_base,
                self.runtime.handler_url(self, "set_raw_scorm_status"))
            get_completion_url = '{}://{}{}'.format(
                scheme, lms_base,
                self.runtime.handler_url(self, "get_scorm_completion"))
        # PreviewModuleSystem (runtime Mixin from Studio) won't have a hostname
        else:
            # we don't want to get/set SCORM status from preview
            get_url = set_url = get_completion_url = '#'

        # if display type is popup, don't use the full window width for the host iframe
        iframe_width = self.display_type == 'popup' and DEFAULT_IFRAME_WIDTH or self.display_width
        iframe_height = self.display_type == 'popup' and DEFAULT_IFRAME_HEIGHT or self.display_height
        show_popup_manually = True if self.display_type == 'popup' and self.popup_launch_type == 'manual' else False
        lock_next_module = self.is_next_module_locked and self.scorm_progress < constants.MAX_PROGRESS_VALUE
        try:
            player_config = json.loads(self.player_configuration)
        except ValueError:
            player_config = {}

        frag = Fragment()
        frag.add_content(
            MakoTemplate(text=html.format(
                self=self,
                scorm_player_url=scorm_player_url,
                get_url=get_url,
                set_url=set_url,
                get_completion_url=get_completion_url,
                iframe_width=iframe_width,
                iframe_height=iframe_height,
                player_config=player_config,
                show_popup_manually=show_popup_manually,
                scorm_file=course_directory,
                is_next_module_locked=lock_next_module)).render_unicode())

        frag.add_css(self.resource_string("static/css/scormxblock.css"))
        context['block_id'] = self.url_name
        js = self.resource_string("static/js/src/scormxblock.js")
        jsfrag = MakoTemplate(js).render_unicode(**context)
        frag.add_javascript(jsfrag)

        # TODO: this will only work to display staff debug info if 'scormxblock' is one of the
        # categories of blocks that are specified in lms/templates/staff_problem_info.html so this will
        # for now have to be overridden in theme or directly in edx-platform
        # TODO: is there another way to approach this?  key's location.category isn't mutable to spoof 'problem',
        # like setting the name in the entry point to 'problem'.  Doesn't seem like a good idea.  Better to
        # have 'staff debuggable' categories configurable in settings or have an XBlock declare itself staff debuggable
        if SCORM_DISPLAY_STAFF_DEBUG_INFO and not authoring:  # don't show for author preview
            from courseware.access import has_access
            from courseware.courses import get_course_by_id

            course = get_course_by_id(self.xmodule_runtime.course_id)
            dj_user = self.xmodule_runtime._services['user']._django_user
            has_instructor_access = bool(
                has_access(dj_user, 'instructor', course))
            if has_instructor_access:
                disable_staff_debug_info = settings.FEATURES.get(
                    'DISPLAY_DEBUG_INFO_TO_STAFF', True) and False or True
                block = self
                view = 'student_view'
                frag = add_staff_markup(dj_user, has_instructor_access,
                                        disable_staff_debug_info, block, view,
                                        frag, context)

        frag.initialize_js('ScormXBlock_{0}'.format(context['block_id']))
        return frag
예제 #14
0
 def author_view(self, context=None):
     html = self.render_template("static/html/author_view.html", context)
     frag = Fragment(html)
     return frag
예제 #15
0
    def student_view(self, context=None):

        # runtime error
        if not hasattr(self.runtime, "anonymous_student_id"):
            return self.message_view(
                "Error in uc_docker (get anonymous student id)",
                "Cannot get anonymous_student_id in runtime", context)

        # preview in studio
        if self.runtime.anonymous_student_id == "student":

            result, message = GitLabUtil.get_user_projects(
                self.git_host, self.git_port, self.git_teacher_token)
            if not result:
                return self.message_view(
                    "Error in uc_docker (get git projects)",
                    "Cannot get user's projects in git", context)

            context_dict = {"labs": self.labs, "message": ""}
            fragment = Fragment()
            fragment.add_content(
                Util.render_template('static/html/uc_lab.html', context_dict))
            fragment.add_css(Util.load_resource("static/css/uc_docker.css"))
            fragment.add_javascript(
                Util.load_resource("static/js/src/uc_lab.js"))
            fragment.initialize_js("UcDockerXBlock")
            return fragment

        # student view in open-edx
        if self.is_new:
            # create git account when first visiting
            student = self.runtime.get_real_user(
                self.runtime.anonymous_student_id)
            email = student.email
            name = student.first_name + " " + student.last_name
            username = student.username
            self.git_password = Util.create_random_password()
            self.save()
            # first_name, last_name are empty
            if name == " ":
                name = username
            self.logger.info("password is " + self.git_password)

            self.logger.info(self.git_host + "," + str(self.git_port) + "," +
                             self.git_admin_token + "," + name + "," +
                             username + "," + email + "," + self.git_password)
            result, message = GitLabUtil.create_account(
                self.git_host, self.git_port, self.git_admin_token, name,
                username, email, self.git_password)
            self.logger.info("create_account result:")
            self.logger.info(result)
            self.logger.info(message)
            if not result:
                return self.message_view(
                    "Error in uc_docker (create git account)", message,
                    context)

            result, message = GitLabUtil.login(self.git_host, self.git_port,
                                               username, self.git_password)
            self.logger.info("login result:")
            self.logger.info(result)
            self.logger.info(message)
            if not result:
                return self.message_view(
                    "Error in uc_docker (login git account)", message, context)

            try:
                message = json.loads(message)
                self.git_id = message["id"]
                self.git_user_token = message["private_token"]
                self.save()

            except Exception, ex:
                return self.message_view(
                    "Error in uc_docker (load json string)", message, context)

            try:
                self.private_key, self.public_key = Util.gen_ssh_keys(email)
                self.logger.info("private_key:" + self.private_key)
                self.save()
                conn = pymongo.Connection('192.168.122.183', 27017)
                db = conn.test
                token = db.token
                token.insert({
                    "username": username,
                    "token": message["private_token"],
                    "password": self.git_password,
                    "private_key": self.private_key,
                    "public_key": self.public_key
                })
                conn.disconnect()

            except Exception, ex:
                return self.message_view("Error in uc_docker (gen ssh key)",
                                         ex, context)
예제 #16
0
 def student_view(self, context):
     """
     Render a student view with context
     """
     self.register_context(context)
     return Fragment()
예제 #17
0
    def student_view(self, context):
        display_items = self.get_display_items()

        # If we're rendering this sequence, but no position is set yet,
        # or exceeds the length of the displayable items,
        # default the position to the first element
        if context.get('requested_child') == 'first':
            self.position = 1
        elif context.get('requested_child') == 'last':
            self.position = len(display_items) or None
        elif self.position is None or self.position > len(display_items):
            self.position = 1

        ## Returns a set of all types of all sub-children
        contents = []

        fragment = Fragment()
        context = context or {}

        bookmarks_service = self.runtime.service(self, "bookmarks")
        context["username"] = self.runtime.service(
            self, "user").get_current_user().opt_attrs['edx-platform.username']

        parent_module = self.get_parent()
        display_names = [
            parent_module.display_name_with_default,
            self.display_name_with_default
        ]

        # We do this up here because proctored exam functionality could bypass
        # rendering after this section.
        self._capture_basic_metrics()

        # Is this sequential part of a timed or proctored exam?
        if self.is_time_limited:
            view_html = self._time_limited_student_view(context)

            # Do we have an alternate rendering
            # from the edx_proctoring subsystem?
            if view_html:
                fragment.add_content(view_html)
                return fragment

        for child in display_items:
            is_bookmarked = bookmarks_service.is_bookmarked(
                usage_key=child.scope_ids.usage_id)
            context["bookmarked"] = is_bookmarked

            progress = child.get_progress()
            rendered_child = child.render(STUDENT_VIEW, context)
            fragment.add_frag_resources(rendered_child)

            # `titles` is a list of titles to inject into the sequential tooltip display.
            # We omit any blank titles to avoid blank lines in the tooltip display.
            titles = [
                title.strip() for title in child.get_content_titles()
                if title.strip()
            ]
            childinfo = {
                'content':
                rendered_child.content,
                'title':
                "\n".join(titles),
                'page_title':
                titles[0] if titles else '',
                'progress_status':
                Progress.to_js_status_str(progress),
                'progress_detail':
                Progress.to_js_detail_str(progress),
                'type':
                child.get_icon_class(),
                'id':
                child.scope_ids.usage_id.to_deprecated_string(),
                'bookmarked':
                is_bookmarked,
                'path':
                " > ".join(display_names + [child.display_name_with_default]),
            }
            if childinfo['title'] == '':
                childinfo['title'] = child.display_name_with_default_escaped
            contents.append(childinfo)

        params = {
            'items':
            contents,
            'element_id':
            self.location.html_id(),
            'item_id':
            self.location.to_deprecated_string(),
            'position':
            self.position,
            'tag':
            self.location.category,
            'ajax_url':
            self.system.ajax_url,
            'next_url':
            _compute_next_url(
                self.location,
                parent_module,
                context.get('redirect_url_func'),
            ),
            'prev_url':
            _compute_previous_url(
                self.location,
                parent_module,
                context.get('redirect_url_func'),
            ),
        }

        fragment.add_content(
            self.system.render_template("seq_module.html", params))

        self._capture_full_seq_item_metrics(display_items)
        self._capture_current_unit_metrics(display_items)

        # Get all descendant XBlock types and counts
        return fragment
예제 #18
0
 def student_view(self, context=None):  # pylint: disable=W0613
     """A view, with the default name."""
     return Fragment(u"This is student view!")
예제 #19
0
    def studio_view(self, context):
        """
        Editing view in Studio
        """
        js_templates = loader.load_unicode('/templates/html/js_templates.html')
        # Get an 'id_suffix' string that is unique for this block.
        # We append it to HTML element ID attributes to ensure multiple instances of the DnDv2 block
        # on the same page don't share the same ID value.
        # We avoid using ID attributes in preference to classes, but sometimes we still need IDs to
        # connect 'for' and 'aria-describedby' attributes to the associated elements.
        id_suffix = self._get_block_id()
        js_templates = js_templates.replace('{{id_suffix}}', id_suffix)
        context = {
            'js_templates': js_templates,
            'id_suffix': id_suffix,
            'fields': self.fields,
            'self': self,
            'data': urllib.quote(json.dumps(self.data)),
        }

        fragment = Fragment()
        fragment.add_content(
            loader.render_django_template(
                '/templates/html/drag_and_drop_edit.html',
                context=context,
                i18n_service=self.i18n_service))
        css_urls = ('public/css/drag_and_drop_edit.css', )
        js_urls = [
            'public/js/vendor/handlebars-v1.1.2.js',
            'public/js/drag_and_drop_edit.js',
        ]

        statici18n_js_url = self._get_statici18n_js_url()
        if statici18n_js_url:
            js_urls.append(statici18n_js_url)

        for css_url in css_urls:
            fragment.add_css_url(self.runtime.local_resource_url(
                self, css_url))
        for js_url in js_urls:
            fragment.add_javascript_url(
                self.runtime.local_resource_url(self, js_url))

        # Do a bit of manipulation so we get the appearance of a list of zone options on
        # items that still have just a single zone stored

        items = self.data.get('items', [])

        for item in items:
            zones = self.get_item_zones(item['id'])
            # Note that we appear to be mutating the state of the XBlock here, but because
            # the change won't be committed, we're actually just affecting the data that
            # we're going to send to the client, not what's saved in the backing store.
            item['zones'] = zones
            item.pop('zone', None)

        fragment.initialize_js(
            'DragAndDropEditBlock', {
                'data': self.data,
                'target_img_expanded_url': self.target_img_expanded_url,
                'default_background_image_url':
                self.default_background_image_url,
            })

        return fragment
예제 #20
0
 def another_view(self, context=None):  # pylint: disable=W0613
     """A secondary view for this block."""
     return Fragment(u"This is another view!")
예제 #21
0
 def fallback_view(self, _view_name, context=None):
     """Provide a fallback view handler"""
     context = context or {}
     return Fragment(Template(self.content).substitute(**context))
예제 #22
0
 def student_view(self, context=None):  # pylint: disable=W0613
     """Provide the default view."""
     body = u"The data: %r." % self.the_data
     body += u":::%s:::" % self.runtime.handler_url(self, "update_the_data")
     return Fragment(body)
예제 #23
0
    def student_view(self, context):
        """
        Player view, displayed to the student
        """
        # Skin file path according to block type
        if hasattr(self, 'lightchild_block_type'):
            json_config_url = self.resource_url(
                OoyalaPlayerLightChildBlock.lightchild_block_type,
                SKIN_FILE_PATH)
            bit_movin_player_url = self.resource_url(
                OoyalaPlayerLightChildBlock.lightchild_block_type,
                BIT_MOVIN_PLAYER_PATH)
        else:
            json_config_url = self.resource_url(self.scope_ids.block_type,
                                                SKIN_FILE_PATH)
            bit_movin_player_url = self.resource_url(self.scope_ids.block_type,
                                                     BIT_MOVIN_PLAYER_PATH)

        dom_id = 'ooyala-' + self._get_unique_id()

        overlay_fragments = ""
        for overlay in self.overlays:
            overlay_fragments += overlay.render()

        transcript = self.transcript.render(i18n_service=self.i18n_service)

        context = self.player_token()
        context.update({
            'title': self.display_name,
            'cc_lang': self.cc_language_preference,
            'cc_disabled': self.disable_cc_and_translations,
            'pcode': self.pcode,
            'content_id': self.content_id,
            'player_id': self.player_id,
            'dom_id': dom_id,
            'overlay_fragments': overlay_fragments,
            'transcript': transcript,
            'width': self.width,
            'height': self.height,
            'autoplay': self.autoplay,
            'config_url': json_config_url,
            'complete_percentage': COMPLETION_VIDEO_COMPLETE_PERCENTAGE,
            'bit_movin_player': bit_movin_player_url,
        })

        JS_URLS = [
            self.local_resource_url(self, 'public/build/player_all.min.js'),
            '//p3.3playmedia.com/p3sdk.current.js',
        ]
        CSS_URLS = [
            self.local_resource_url(self, 'public/build/player_all.min.css'),
        ]

        fragment = Fragment()
        fragment.add_content(
            render_template('/templates/html/ooyala_player.html', context))

        for url in JS_URLS:
            fragment.add_javascript_url(url)

        for url in CSS_URLS:
            fragment.add_css_url(url)

        fragment.initialize_js('OoyalaPlayerBlock')

        if self.fire_progress_event_on_student_view:
            # In certain cases we want to know when a student has visited a video player
            # as an indication that they are progressing through a course
            # Progress *does not* mean progress over viewing a video (i.e. elapsed time)
            self.runtime.publish(self, 'completion', {"completion": 1.0})

        return fragment
예제 #24
0
 def render_child_placeholder(self, block, view_name, context):
     """
     Renders a placeholder XBlock.
     """
     return self.wrap_xblock(block, view_name, Fragment(), context)
    def student_view(self, context):
        """
        Player view, displayed to the student
        """

        xmltree = etree.fromstring(self.data)

        description = self._get_description(xmltree)
        hotspots = self._get_hotspots(xmltree)
        background = self._get_background(xmltree)
        has_youtube = False
        has_ooyala = False

        for hotspot in hotspots:
            width = 'width:{0}px'.format(
                hotspot.feedback.width
            ) if hotspot.feedback.width else 'width:300px'
            height = 'height:{0}px'.format(
                hotspot.feedback.height) if hotspot.feedback.height else ''
            max_height = ''
            if not hotspot.feedback.height:
                max_height = 'max-height:{0}px'.format(hotspot.feedback.max_height) if \
                             hotspot.feedback.max_height else 'max-height:300px'

            hotspot.reveal_style = 'style="{0};{1};{2}"'.format(
                width, height, max_height)
            if hotspot.feedback.youtube:
                has_youtube = True

            if hotspot.feedback.ooyala:
                has_ooyala = True

        context = {
            'title': self.display_name,
            'hotspot_coordinates_centered': self.hotspot_coordinates_centered,
            'description_html': description,
            'hotspots': hotspots,
            'background': background,
        }

        fragment = Fragment()
        fragment.add_content(
            loader.render_django_template(
                '/templates/html/image_explorer.html',
                context=context,
                i18n_service=self.runtime.service(self, 'i18n')))
        fragment.add_css_url(
            self.runtime.local_resource_url(self,
                                            'public/css/image_explorer.css'))
        fragment.add_javascript_url(
            self.runtime.local_resource_url(self,
                                            'public/js/image_explorer.js'))
        if has_youtube:
            fragment.add_javascript_url('https://www.youtube.com/iframe_api')

        if has_ooyala:
            fragment.add_javascript_url(
                'https://player.ooyala.com/v3/635104fd644c4170ae227af2de27deab?platform=html5-priority'
            )
            fragment.add_javascript_url(
                self.runtime.local_resource_url(self,
                                                'public/js/ooyala_player.js'))

        fragment.initialize_js('ImageExplorerBlock')

        return fragment
예제 #26
0
    def studio_view(self, _context):
        """
        Render a form for XBlock editing.
        """
        fragment = Fragment()
        player = self.get_player()
        languages = [{
            'label': label,
            'code': lang
        } for lang, label in ALL_LANGUAGES]
        languages.sort(key=lambda l: l['label'])
        transcripts = self.get_enabled_transcripts()
        download_transcript_handler_url = self.runtime.handler_url(
            self, 'download_transcript')
        auth_error_message = ''
        # Authenticate to API of the player video platform and update metadata with auth information.
        # Note that there is no need to authenticate to Youtube API,
        # whilst for Wistia, a sample authorised request is to be made to ensure authentication succeeded,
        # since it is needed for the auth status message generation and the player's state update with auth status.
        if self.token:
            _auth_data, auth_error_message = self.authenticate_video_api(
                self.token.encode(encoding='utf-8'))

        initial_default_transcripts, transcripts_autoupload_message = self._update_default_transcripts(
            player, transcripts)
        log.debug("Fetched default transcripts: {}".format(
            initial_default_transcripts))

        # Prepare basic_fields and advanced_fields for them to be rendered
        basic_fields = self.prepare_studio_editor_fields(player.basic_fields)
        advanced_fields = self.prepare_studio_editor_fields(
            player.advanced_fields)
        context = {
            'advanced_fields':
            advanced_fields,
            'auth_error_message':
            auth_error_message,
            'basic_fields':
            basic_fields,
            'courseKey':
            self.course_key,
            'languages':
            languages,
            'player_name':
            self.player_name,  # for players identification
            'players':
            PlayerName,
            'sources':
            TranscriptSource.to_dict().items(),
            # transcripts context:
            'transcripts':
            filter_transcripts_by_source(
                transcripts,
                sources=[TranscriptSource.THREE_PLAY_MEDIA],
                exclude=True),
            'transcripts_fields':
            self.prepare_studio_editor_fields(player.trans_fields),
            'three_pm_fields':
            self.prepare_studio_editor_fields(player.three_pm_fields),
            'transcripts_type':
            '3PM' if self.threeplaymedia_streaming else 'manual',
            'default_transcripts':
            self.default_transcripts,
            'enabled_default_transcripts':
            filter_transcripts_by_source(transcripts),
            'enabled_managed_transcripts':
            self.get_enabled_managed_transcripts(),
            'initial_default_transcripts':
            initial_default_transcripts,
            'transcripts_autoupload_message':
            transcripts_autoupload_message,
            'download_transcript_handler_url':
            download_transcript_handler_url,
        }

        fragment.content = render_template('studio-edit.html', **context)
        fragment.add_css(resource_string("static/css/student-view.css"))
        fragment.add_css(resource_string("static/css/transcripts-upload.css"))
        fragment.add_css(resource_string("static/css/studio-edit.css"))
        fragment.add_css(
            resource_string("static/css/studio-edit-accordion.css"))
        fragment.add_javascript(
            resource_string("static/js/runtime-handlers.js"))
        fragment.add_javascript(
            resource_string("static/js/studio-edit/utils.js"))
        fragment.add_javascript(
            resource_string("static/js/studio-edit/studio-edit.js"))
        fragment.add_javascript(
            resource_string("static/js/studio-edit/transcripts-autoload.js"))
        fragment.add_javascript(
            resource_string(
                "static/js/studio-edit/transcripts-manual-upload.js"))
        fragment.initialize_js('StudioEditableXBlock')
        return fragment
예제 #27
0
    def recap_blocks_listing_view(self, context=None):
        """This view is used in the Racap tab in the LMS Instructor Dashboard
        to display all available course Recap xblocks.

        Args:
            context: contains two items:
                "recap_items" - all course items with names and parents, example:
                    [{"parent_name": "Vertical name",
                      "name": "Recap Display Name",
                     }, ...]
        Returns:
            (Fragment): The HTML Fragment for this XBlock.
        """
        course_id = self.location.course_key
        recap_blocks = self.get_recap_course_blocks(course_id)
        recap_name_list = []

        for block in recap_blocks:
            recap_name_list.append((block.display_name, block.xblock_list))

        make_pdf_json = reverse('xblock_handler', args=[course_id, block.location, 'make_pdf_json'])
        refresh_table = reverse('xblock_handler', args=[course_id, block.location, 'refresh_table'])

        user = self.runtime.get_real_user(self.runtime.anonymous_student_id)
        lang_prefs = get_user_preference(user, LANGUAGE_KEY)

        context_dict = {
            "make_pdf_json": make_pdf_json,
            "refresh_table": refresh_table,
            "recap_name_list": recap_name_list,
            "lang_prefs": lang_prefs
        }

        instructor_dashboard_fragment = Fragment()
        instructor_dashboard_fragment.content = loader.render_django_template(
            'static/html/recap_dashboard.html',
            context_dict
        )
        instructor_dashboard_fragment.add_css(
            self.resource_string("static/css/recap.css")
        )
        instructor_dashboard_fragment.add_css(
            self.resource_string("public/DataTables/css/jquery.dataTables.css")
        )
        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/FileSaver.js/FileSaver.min.js'
            )
        )
        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/jspdf.min.js'
            )
        )
        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/html2canvas.min.js'
            )
        )
        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/jsPDF-1.3.2/html2pdf.js'
            )
        )
        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                'public/DataTables/js/jquery.dataTables.js'
            )
        )

        instructor_dashboard_fragment.add_javascript_url(
            self.runtime.local_resource_url(
                self,
                "public/recap_dashboard.js"
            )
        )
        instructor_dashboard_fragment.initialize_js('RecapDashboard')

        return instructor_dashboard_fragment
예제 #28
0
        else:
            # TODO update git account
            student = self.runtime.get_real_user(
                self.runtime.anonymous_student_id)
            username = student.username
            print 'OK'

        context_dict = {
            "labs": self._get_available_labs(),
            "dockers": self.dockers,
            "password": self.git_password,
            "username": username,
            "message": "",
            "report": ""
        }
        fragment = Fragment()
        fragment.add_content(
            Util.render_template('static/html/uc_docker.html', context_dict))
        fragment.add_css(Util.load_resource("static/css/uc_docker.css"))
        fragment.add_javascript(
            Util.load_resource("static/js/src/uc_docker.js"))
        fragment.initialize_js("UcDockerXBlock")
        return fragment

    def studio_view(self, context=None):
        # to add new lab
        context_dict = {
            "labs": self.labs,
            "docker_file": """FROM uclassroom/ucore-vnc-base
MAINTAINER ggxx<*****@*****.**>
예제 #29
0
def index(request, course_id, chapter=None, section=None,
          position=None):
    """
    Displays courseware accordion and associated content.  If course, chapter,
    and section are all specified, renders the page, or returns an error if they
    are invalid.

    If section is not specified, displays the accordion opened to the right chapter.

    If neither chapter or section are specified, redirects to user's most recent
    chapter, or the first chapter if this is the user's first visit.

    Arguments:

     - request    : HTTP request
     - course_id  : course id (str: ORG/course/URL_NAME)
     - chapter    : chapter url_name (str)
     - section    : section url_name (str)
     - position   : position in module, eg of <sequential> module (str)

    Returns:

     - HTTPresponse
    """
    user = User.objects.prefetch_related("groups").get(id=request.user.id)
    request.user = user  # keep just one instance of User
    course = get_course_with_access(user, course_id, 'load', depth=2)
    staff_access = has_access(user, course, 'staff')
    registered = registered_for_course(course, user)
    if not registered:
        # TODO (vshnayder): do course instructors need to be registered to see course?
        log.debug(u'User %s tried to view course %s but is not enrolled', user, course.location.url())
        return redirect(reverse('about_course', args=[course.id]))

    masq = setup_masquerade(request, staff_access)

    try:
        field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
            course.id, user, course, depth=2)

        course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id)
        if course_module is None:
            log.warning(u'If you see this, something went wrong: if we got this'
                        u' far, should have gotten a course module for this user')
            return redirect(reverse('about_course', args=[course.id]))

        studio_url = get_studio_url(course_id, 'course')

        if chapter is None:
            return redirect_to_course_position(course_module)

        context = {
            'csrf': csrf(request)['csrf_token'],
            'accordion': render_accordion(request, course, chapter, section, field_data_cache),
            'COURSE_TITLE': course.display_name_with_default,
            'course': course,
            'init': '',
            'fragment': Fragment(),
            'staff_access': staff_access,
            'studio_url': studio_url,
            'masquerade': masq,
            'xqa_server': settings.FEATURES.get('USE_XQA_SERVER', 'http://*****:*****@content-qa.mitx.mit.edu/xqa'),
            'reverifications': fetch_reverify_banner_info(request, course_id),
        }

        # Only show the chat if it's enabled by the course and in the
        # settings.
        show_chat = course.show_chat and settings.FEATURES['ENABLE_CHAT']
        if show_chat:
            context['chat'] = chat_settings(course, user)
            # If we couldn't load the chat settings, then don't show
            # the widget in the courseware.
            if context['chat'] is None:
                show_chat = False

        context['show_chat'] = show_chat

        chapter_descriptor = course.get_child_by(lambda m: m.url_name == chapter)
        if chapter_descriptor is not None:
            save_child_position(course_module, chapter)
        else:
            raise Http404('No chapter descriptor found with name {}'.format(chapter))

        chapter_module = course_module.get_child_by(lambda m: m.url_name == chapter)
        if chapter_module is None:
            # User may be trying to access a chapter that isn't live yet
            if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                log.debug('staff masq as student: no chapter %s' % chapter)
                return redirect(reverse('courseware', args=[course.id]))
            raise Http404

        if section is not None:
            section_descriptor = chapter_descriptor.get_child_by(lambda m: m.url_name == section)
            if section_descriptor is None:
                # Specifically asked-for section doesn't exist
                if masq == 'student':  # if staff is masquerading as student be kinder, don't 404
                    log.debug('staff masq as student: no section %s' % section)
                    return redirect(reverse('courseware', args=[course.id]))
                raise Http404

            # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
            # which will prefetch the children more efficiently than doing a recursive load
            section_descriptor = modulestore().get_instance(course.id, section_descriptor.location, depth=None)

            # Load all descendants of the section, because we're going to display its
            # html, which in general will need all of its children
            section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
                course_id, user, section_descriptor, depth=None)

            section_module = get_module_for_descriptor(
                request.user,
                request,
                section_descriptor,
                section_field_data_cache,
                course_id,
                position
            )

            if section_module is None:
                # User may be trying to be clever and access something
                # they don't have access to.
                raise Http404

            # Save where we are in the chapter
            save_child_position(chapter_module, section)
            context['fragment'] = section_module.render('student_view')
            context['section_title'] = section_descriptor.display_name_with_default
        else:
            # section is none, so display a message
            studio_url = get_studio_url(course_id, 'course')
            prev_section = get_current_child(chapter_module)
            if prev_section is None:
                # Something went wrong -- perhaps this chapter has no sections visible to the user
                raise Http404
            prev_section_url = reverse('courseware_section', kwargs={'course_id': course_id,
                                                                     'chapter': chapter_descriptor.url_name,
                                                                     'section': prev_section.url_name})
            context['fragment'] = Fragment(content=render_to_string(
                'courseware/welcome-back.html',
                {
                    'course': course,
                    'studio_url': studio_url,
                    'chapter_module': chapter_module,
                    'prev_section': prev_section,
                    'prev_section_url': prev_section_url
                }
            ))

        result = render_to_response('courseware/courseware.html', context)
    except Exception as e:
        if isinstance(e, Http404):
            # let it propagate
            raise

        # In production, don't want to let a 500 out for any reason
        if settings.DEBUG:
            raise
        else:
            log.exception(
                u"Error in index view: user={user}, course={course}, chapter={chapter}"
                u" section={section} position={position}".format(
                    user=user,
                    course=course,
                    chapter=chapter,
                    section=section,
                    position=position
                ))
            try:
                result = render_to_response('courseware/courseware-error.html', {
                    'staff_access': staff_access,
                    'course': course
                })
            except:
                # Let the exception propagate, relying on global config to at
                # at least return a nice error message
                log.exception("Error while rendering courseware-error page")
                raise

    return result
예제 #30
0
def xblock_view_handler(request, package_id, view_name, tag=None, branch=None, version_guid=None, block=None):
    """
    The restful handler for requests for rendered xblock views.

    Returns a json object containing two keys:
        html: The rendered html of the view
        resources: A list of tuples where the first element is the resource hash, and
            the second is the resource description
    """
    locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
    if not has_course_access(request.user, locator):
        raise PermissionDenied()
    old_location = loc_mapper().translate_locator_to_location(locator)

    accept_header = request.META.get('HTTP_ACCEPT', 'application/json')

    if 'application/json' in accept_header:
        store = get_modulestore(old_location)
        component = store.get_item(old_location)

        # wrap the generated fragment in the xmodule_editor div so that the javascript
        # can bind to it correctly
        component.runtime.wrappers.append(partial(wrap_xblock, 'StudioRuntime'))

        if view_name == 'studio_view':
            try:
                fragment = component.render('studio_view')
            # catch exceptions indiscriminately, since after this point they escape the
            # dungeon and surface as uneditable, unsaveable, and undeletable
            # component-goblins.
            except Exception as exc:                          # pylint: disable=w0703
                log.debug("unable to render studio_view for %r", component, exc_info=True)
                fragment = Fragment(render_to_string('html_error.html', {'message': str(exc)}))

            # change not authored by requestor but by xblocks.
            store.update_item(component, None)

        elif view_name == 'student_view' and component.has_children:
            # For non-leaf xblocks on the unit page, show the special rendering
            # which links to the new container page.
            html = render_to_string('container_xblock_component.html', {
                'xblock': component,
                'locator': locator,
                'reordering_enabled': True,
            })
            return JsonResponse({
                'html': html,
                'resources': [],
            })
        elif view_name in ('student_view', 'container_preview'):
            is_container_view = (view_name == 'container_preview')
            component_publish_state = compute_publish_state(component)
            is_read_only_view = component_publish_state == PublishState.public

            # Only show the new style HTML for the container view, i.e. for non-verticals
            # Note: this special case logic can be removed once the unit page is replaced
            # with the new container view.
            context = {
                'runtime_type': 'studio',
                'container_view': is_container_view,
                'read_only': is_read_only_view,
                'root_xblock': component,
            }

            fragment = get_preview_fragment(request, component, context)
            # For old-style pages (such as unit and static pages), wrap the preview with
            # the component div. Note that the container view recursively adds headers
            # into the preview fragment, so we don't want to add another header here.
            if not is_container_view:
                fragment.content = render_to_string('component.html', {
                    'preview': fragment.content,
                    'label': component.display_name or component.scope_ids.block_type,

                    # Native XBlocks are responsible for persisting their own data,
                    # so they are also responsible for providing save/cancel buttons.
                    'show_save_cancel': isinstance(component, xmodule.x_module.XModuleDescriptor),
                })
        else:
            raise Http404

        hashed_resources = OrderedDict()
        for resource in fragment.resources:
            hashed_resources[hash_resource(resource)] = resource

        return JsonResponse({
            'html': fragment.content,
            'resources': hashed_resources.items()
        })

    else:
        return HttpResponse(status=406)