Пример #1
0
    def test_course_image(self):
        url = course_image_url(self.course)
        self.assertTrue(url.startswith('/c4x/'))

        self.course.static_asset_path = "toy_course_dir"
        url = course_image_url(self.course)
        self.assertTrue(url.startswith('/static/toy_course_dir/'))
        self.course.static_asset_path = ""
Пример #2
0
def get_course_info(course):
    """Returns an object containing original edX course and some complementary properties."""
    about_sections = {}
    for field in ABOUT_SECTION_FIELDS:
        about_sections[field] = get_course_about_section(course, field)
    about_sections['effort'] = about_sections['effort'].replace('\n', '')  # clean the many CRs
    if about_sections['video']:
        try:  # edX stores the Youtube iframe HTML code, let's extract the Dailymotion Cloud ID
            about_sections['video'] = re.findall('www.youtube.com/embed/(?P<hash>[\w]+)\?', about_sections['video'])[0]
        except IndexError:
            pass
    try:
        funcourse = Course.objects.get(key=course.id)
    except Course.DoesNotExist:
        funcourse = None

    course_info = FunCourse(course=course,
            fun=funcourse,
            course_image_url=course_image_url(course),
            students_count=CourseEnrollment.objects.filter(course_id=course.id).count(),
            url='https://%s%s' % (settings.LMS_BASE,
                    reverse('about_course', args=[course.id.to_deprecated_string()])),
            studio_url=get_cms_course_link(course),
            **about_sections
            )
    return course_info
Пример #3
0
def _update_course_context(request, context, course, platform_name):
    """
    Updates context dictionary with course info.
    """
    context['full_course_image_url'] = request.build_absolute_uri(
        course_image_url(course))
    course_title_from_cert = context['certificate_data'].get(
        'course_title', '')
    accomplishment_copy_course_name = course_title_from_cert if course_title_from_cert else course.display_name
    context[
        'accomplishment_copy_course_name'] = accomplishment_copy_course_name
    course_number = course.display_coursenumber if course.display_coursenumber else course.number
    context['course_number'] = course_number
    if context['organization_long_name']:
        # Translators:  This text represents the description of course
        context['accomplishment_copy_course_description'] = _(
            'a course of study offered by {partner_short_name}, '
            'an online learning initiative of {partner_long_name} '
            'through {platform_name}.').format(
                partner_short_name=context['organization_short_name'],
                partner_long_name=context['organization_long_name'],
                platform_name=platform_name)
    else:
        # Translators:  This text represents the description of course
        context['accomplishment_copy_course_description'] = _(
            'a course of study offered by {partner_short_name}, '
            'through {platform_name}.').format(
                partner_short_name=context['organization_short_name'],
                platform_name=platform_name)
Пример #4
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id.to_deprecated_string()
    course_title = course.display_name
    course_end_date = get_default_time_display(course.end)
    course_url = 'https://{}{}'.format(
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id}))
    image_url = u'https://{}{}'.format(settings.SITE_NAME,
                                       course_image_url(course))
    email_context = {
        'course_title':
        course_title,
        'course_url':
        course_url,
        'course_image_url':
        image_url,
        'course_end_date':
        course_end_date,
        'account_settings_url':
        'https://{}{}'.format(settings.SITE_NAME, reverse('account_settings')),
        'platform_name':
        settings.PLATFORM_NAME,
    }
    return email_context
Пример #5
0
def json_courses(request, courses):
    c_list = []
    for c in courses:
        m_list = []
        img_url = course_image_url(c)
        short_disc = get_course_about_section(c, 'short_description')
        about_url = reverse('about_course', args=[c.id.to_deprecated_string()])
        m_list.append(c.id.to_deprecated_string())
        m_list.append(c.is_newish)
        m_list.append(c.display_number_with_default)
        m_list.append(c.display_name_with_default)
        m_list.append(c.display_org_with_default)
        m_list.append(c.start_date_is_still_default)
        m_list.append(c.start_date_text)
        m_list.append(img_url)
        m_list.append(short_disc)
        m_list.append(about_url)
        m_list.append(len(courses))
        c_list.append(m_list)

    json_list = json.dumps([{
        'id': a,
        'is_new': b,
        'number': n,
        'name': m,
        'org': o,
        'start_date_is_still': d,
        'start_date_text': s,
        'img_url': i,
        'short_disc': di,
        'about_url': ab,
        'lenth': l
    } for a, b, n, m, o, d, s, i, di, ab, l in c_list])

    return json_list
Пример #6
0
 def test_spaces_in_image_name(self):
     # Verify that image names with spaces in them are cleaned
     course = CourseFactory.create(course_image=u'before after.jpg')
     self.assertEquals(
         course_image_url(course),
         '/c4x/{org}/{course}/asset/before_after.jpg'.format(
             org=course.location.org, course=course.location.course))
Пример #7
0
 def test_non_ascii_image_name(self):
     course = self.process_xml(
         xml.CourseFactory.build(
             course_image=u'before_\N{SNOWMAN}_after.jpg'))
     self.assertEquals(
         course_image_url(course),
         u'/static/xml_test_course/before_\N{SNOWMAN}_after.jpg')
Пример #8
0
def course_infos(course):
    d = {
        'course_image_url': course_image_url(course)
    }
    for section in ['title', 'university']:
        d[section] = get_about_section(course, section)
    return d
Пример #9
0
    def send_grandfather_email(self, user, certificates, mock_run=False):
        """
        Send the 'grandfathered' email informing historical students that they
        may now post their certificates on their LinkedIn profiles.
        """
        courses_list = []
        for cert in certificates:
            course = get_course_by_id(cert.course_id)
            course_url = 'https://{}{}'.format(
                settings.SITE_NAME,
                reverse('course_root', kwargs={'course_id': cert.course_id})
            )

            course_title = course.display_name_with_default

            course_img_url = 'https://{}{}'.format(settings.SITE_NAME, course_image_url(course))
            course_end_date = course.end.strftime('%b %Y')
            course_org = course.org

            courses_list.append({
                'course_url': course_url,
                'course_org': course_org,
                'course_title': course_title,
                'course_image_url': course_img_url,
                'course_end_date': course_end_date,
                'linkedin_add_url': self.certificate_url(cert),
            })

        context = {'courses_list': courses_list, 'num_courses': len(courses_list)}
        body = render_to_string('linkedin/linkedin_email.html', context)
        subject = u'{}, Add your Achievements to your LinkedIn Profile'.format(user.profile.name)
        if mock_run:
            return True
        else:
            return self.send_email(user, subject, body)
Пример #10
0
 def test_non_ascii_image_name(self):
     # XML Course images are always stored at /images/course_image.jpg
     course = self.process_xml(
         xml.CourseFactory.build(
             course_image=u'before_\N{SNOWMAN}_after.jpg'))
     self.assertEquals(course_image_url(course),
                       '/static/xml_test_course/images/course_image.jpg')
Пример #11
0
 def test_non_ascii_image_name(self):
     # Verify that non-ascii image names are cleaned
     course = CourseFactory.create(
         course_image=u'before_\N{SNOWMAN}_after.jpg')
     self.assertEquals(
         course_image_url(course),
         '/c4x/{org}/{course}/asset/before___after.jpg'.format(
             org=course.location.org, course=course.location.course))
Пример #12
0
 def test_static_asset_path_course_image_default(self):
     """
     Test that without course_image being set, but static_asset_path
     being set that we get the right course_image url.
     """
     course = CourseFactory.create(static_asset_path="foo")
     self.assertEquals(course_image_url(course),
                       '/static/foo/images/course_image.jpg')
Пример #13
0
def mobi_forum_course_list(request):
    '''
    get all course what user has talked about
    '''
    nr_transaction = newrelic.agent.current_transaction()
    user = request.user
    course_org_filter = microsite.get_value('course_org_filter')

    # Let's filter out any courses in an "org" that has been declared to be
    # in a Microsite
    org_filter_out_set = microsite.get_all_orgs()

    # remove our current Microsite from the "filter out" list, if applicable
    if course_org_filter:
        org_filter_out_set.remove(course_org_filter)

    # Build our (course, enrollment) list for the user, but ignore any courses that no
    # longer exist (because the course IDs have changed). Still, we don't delete those
    # enrollments, because it could have been a data push snafu.
    course_enrollment_pairs = list(get_course_enrollment_pairs(user, course_org_filter, org_filter_out_set))

    show_courseware_links_for = frozenset(course.id for course, _enrollment in course_enrollment_pairs
                                          if has_access(request.user, course, 'load'))
    user_info = cc.User.from_django_user(request.user).to_dict()
    courselist = []
    for course_id in show_courseware_links_for:
        try:
            user_id = user.id
            profiled_user = cc.User(id=user_id, course_id=course_id)

            query_params = {
                'page': request.GET.get('page', 1),
                'per_page': THREADS_PER_PAGE,   # more than threads_per_page to show more activities
            }

            threads, page, num_pages = profiled_user.active_threads(query_params)
            query_params['page'] = page
            query_params['num_pages'] = num_pages

            with newrelic.agent.FunctionTrace(nr_transaction, "get_metadata_for_threads"):
                annotated_content_info = utils.get_metadata_for_threads(course_id, threads, request.user, user_info)
            if annotated_content_info:
                courselist.append(course_id)
        except User.DoesNotExist:
            raise Http404
    course_list = []
    for newcourse in courselist:
        course = course_from_id(newcourse)
        courseid = course.id.replace('/', '.')
        newdict = {
            'imageurl': request.get_host() + course_image_url(course),
            'id': courseid,
            'name': course.display_name
        }
        course_list.append(newdict)

    return JsonResponse({"course-list": course_list})
Пример #14
0
 def test_static_asset_path_course_image_set(self):
     """
     Test that with course_image and static_asset_path both
     being set, that we get the right course_image url.
     """
     course = CourseFactory.create(course_image=u'things_stuff.jpg',
                                   static_asset_path="foo")
     self.assertEquals(course_image_url(course),
                       '/static/foo/things_stuff.jpg')
Пример #15
0
 def test_spaces_in_image_name(self):
     # Verify that image names with spaces in them are cleaned
     course = CourseFactory.create(course_image=u'before after.jpg')
     self.assertEquals(
         course_image_url(course),
         '/c4x/{org}/{course}/asset/before_after.jpg'.format(
             org=course.location.org,
             course=course.location.course
         )
     )
Пример #16
0
 def test_static_asset_path_course_image_default(self):
     """
     Test that without course_image being set, but static_asset_path
     being set that we get the right course_image url.
     """
     course = CourseFactory.create(static_asset_path="foo")
     self.assertEquals(
         course_image_url(course),
         '/static/foo/images/course_image.jpg'
     )
Пример #17
0
 def test_non_ascii_image_name(self):
     # Verify that non-ascii image names are cleaned
     course = CourseFactory.create(course_image=u'before_\N{SNOWMAN}_after.jpg')
     self.assertEquals(
         course_image_url(course),
         '/c4x/{org}/{course}/asset/before___after.jpg'.format(
             org=course.location.org,
             course=course.location.course
         )
     )
Пример #18
0
def courses(request, show_hidden):
    """
    Renders the courses list for the API.

    :param request: The django HttpRequest object.
    :param show_hidden: True or False, (controlled from the urls.py file) to show courses with
                        upcoming enrollment date.

    :return: JsonResponse with a list of the courses.
    """
    courses_list = branding.get_visible_courses()

    if not show_hidden:
        # Using `AnonymousUser()` to hide unpublished courses
        anonymous_user = AnonymousUser()

        # The logic bellow has been copied (with amendments) from `courseware.courses.get_courses`,
        # Just in case something changes with edX releases.
        permission_name = settings.COURSE_CATALOG_VISIBILITY_PERMISSION

        courses_list = [
            c for c in courses_list
            if has_access(anonymous_user, permission_name, c)
        ]

    courses_list = sort_by_announcement(courses_list)
    courses_list = edraak_courses_logic(courses_list)

    courses_json_list = []

    prefix = get_absolute_url_prefix(request)

    for course in courses_list:
        video_tag = get_course_about_section(course, "video")
        youtube_id = video_tag[video_tag.find("embed") + 6:video_tag.find("?")]

        courses_json_list.append({
            "id": unicode(course.id),
            "number": course.display_number_with_default,
            "name": course.display_name_with_default,
            "organization": course.display_org_with_default,
            "description": get_course_about_section(course, "short_description").strip(),
            "startDate": course.start,
            "endDate": course.end,
            "enrollmentStartDate": course.enrollment_start,
            "enrollmentEndDate": course.enrollment_end,
            "overview": get_course_about_section(course, "overview").strip(),
            "aboutPage": prefix + reverse('about_course', args=[unicode(course.id)]),
            "image": prefix + course_image_url(course),
            "state": _get_course_status(course),
            "youtube_id": youtube_id,
            "effort": get_course_about_section(course, "effort").strip(),
        })

    return JsonResponse(courses_json_list)
Пример #19
0
 def test_static_asset_path_course_image_set(self):
     """
     Test that with course_image and static_asset_path both
     being set, that we get the right course_image url.
     """
     course = CourseFactory.create(course_image=u'things_stuff.jpg',
                                   static_asset_path="foo")
     self.assertEquals(
         course_image_url(course),
         '/static/foo/things_stuff.jpg'
     )
Пример #20
0
    def to_native(self, course):
        course_id = unicode(course.id)
        request = self.context.get('request', None)
        if request:
            video_outline_url = reverse(
                'video-summary-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_updates_url = reverse(
                'course-updates-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_handouts_url = reverse(
                'course-handouts-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_about_url = reverse(
                'course-about-detail',
                kwargs={'course_id': course_id},
                request=request
            )
        else:
            video_outline_url = None
            course_updates_url = None
            course_handouts_url = None
            course_about_url = None

        return {
            "id": course_id,
            "name": course.display_name,
            "number": course.display_number_with_default,
            "org": course.display_org_with_default,
            "start": course.start,
            "end": course.end,
            "course_image": course_image_url(course),
            "social_urls": {
                "facebook": course.facebook_url,
            },
            "latest_updates": {
                "video": None
            },
            "video_outline": video_outline_url,
            "course_updates": course_updates_url,
            "course_handouts": course_handouts_url,
            "course_about": course_about_url,
            "subscription_id": course.clean_id(padding_char='_'),
        }
Пример #21
0
def mobi_course_info(request, course, action=None):
    course_logo = course_image_url(course)
    imgurl = course_logo
    if action in ["homefalls", "all", "hot", "latest", "my", "search"]:
        try:
            course_mini_info = course.id.split('/')
            asset_location = StaticContent.compute_location(course_mini_info[0], course_mini_info[1], 'mobi-logo-img.jpg')
            imgurl = StaticContent.get_url_path_from_location(asset_location)
        except:
            print "=========================fail load mobi image==============================="
            print "We will load this info to log"

    return {
        "id": course.id.replace('/', '.'),
        "name": course.display_name_with_default,
        "logo": request.get_host() + course_image_url(course),
        "org": course.display_org_with_default,
        "course_number": course.display_number_with_default,
        "start_date": course.start.strftime("%Y-%m-%d"),
        "about": get_course_about_section(course, 'short_description'),
        "category": course.category,
        "imgurl": request.get_host() + imgurl
    }
Пример #22
0
def mobi_course_info(request, course, action=None):
    course_logo = course_image_url(course)
    imgurl = course_logo
    if action in ["homefalls", "all", "hot", "latest", "my", "search"]:
        try:
            course_mini_info = course.id.split('/')
            asset_location = StaticContent.compute_location(course_mini_info[0], course_mini_info[1], 'mobi-logo-img.jpg')
            imgurl = StaticContent.get_url_path_from_location(asset_location)
        except:
            print "=========================fail load mobi image==============================="
            print "We will load this info to log"

    return {
        "id": course.id.replace('/', '.'),
        "name": course.display_name_with_default,
        "logo": request.get_host() + course_image_url(course),
        "org": course.display_org_with_default,
        "course_number": course.display_number_with_default,
        "start_date": course.start.strftime("%Y-%m-%d"),
        "about": get_course_about_section(course, 'short_description'),
        "category": course.category,
        "imgurl": request.get_host() + imgurl
    }
Пример #23
0
def get_course_info(course_descriptor, course, students_count):
    """Returns an object containing original edX course and some complementary properties."""
    about_sections = get_about_sections(course_descriptor)
    course_info = FunCourse(
        course=course_descriptor,
        fun=course,
        course_image_url=course_image_url(course_descriptor),
        students_count=students_count,
        title=course_descriptor.display_name_with_default,
        university=course_descriptor.display_org_with_default,
        url='https://%s%s' % (settings.LMS_BASE,
                reverse('about_course', args=[course_descriptor.id.to_deprecated_string()])),
        studio_url=get_cms_course_link(course_descriptor),
        **about_sections
    )
    return course_info
Пример #24
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id.to_deprecated_string()
    course_title = course.display_name
    course_url = "https://{}{}".format(settings.SITE_NAME, reverse("course_root", kwargs={"course_id": course_id}))
    image_url = "https://{}{}".format(settings.SITE_NAME, course_image_url(course))
    email_context = {
        "course_title": course_title,
        "course_url": course_url,
        "course_image_url": image_url,
        "account_settings_url": "https://{}{}".format(settings.SITE_NAME, reverse("dashboard")),
        "platform_name": settings.PLATFORM_NAME,
    }
    return email_context
Пример #25
0
    def to_native(self, course):
        course_id = unicode(course.id)
        request = self.context.get('request', None)
        if request:
            video_outline_url = reverse(
                'video-summary-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_updates_url = reverse(
                'course-updates-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_handouts_url = reverse(
                'course-handouts-list',
                kwargs={'course_id': course_id},
                request=request
            )
            course_about_url = reverse(
                'course-about-detail',
                kwargs={'course_id': course_id},
                request=request
            )
        else:
            video_outline_url = None
            course_updates_url = None
            course_handouts_url = None
            course_about_url = None

        return {
            "id": course_id,
            "name": course.display_name,
            "number": course.display_number_with_default,
            "org": course.display_org_with_default,
            "start": course.start,
            "end": course.end,
            "course_image": course_image_url(course),
            "latest_updates": {
                "video": None
            },
            "video_outline": video_outline_url,
            "course_updates": course_updates_url,
            "course_handouts": course_handouts_url,
            "course_about": course_about_url,
        }
Пример #26
0
    def format_course(course):
        format_course_json = {
            "id": course.id,
            "is_new": course.is_newish,
            "course_about_url": reverse('about_course', args=[course.id]),
            "course_number": course.display_number_with_default or "",
            "title": get_course_about_section(course, 'title'),
            "short_description": get_course_about_section(course, "short_description"),
            "img_src": course_image_url(course),
            "university": get_course_about_section(course, 'university'),
            "is_start_date_default": course.start_date_is_still_default,
            }

        if not format_course_json["is_start_date_default"]:
            format_course_json.update({"start_date_text": course.start_date_text})

        return format_course_json
Пример #27
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id
    course_title = course.display_name
    course_url = 'https://{}{}'.format(
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id})
    )
    image_url = 'https://{}{}'.format(settings.SITE_NAME, course_image_url(course))
    email_context = {
        'course_title': course_title,
        'course_url': course_url,
        'course_image_url': image_url,
        'account_settings_url': 'https://{}{}'.format(settings.SITE_NAME, reverse('dashboard')),
        'platform_name': settings.PLATFORM_NAME,
    }
    return email_context
Пример #28
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id
    course_title = course.display_name
    course_url = 'https://{}{}'.format(
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id})
    )
    image_url = 'https://{}{}'.format(settings.SITE_NAME, course_image_url(course))
    email_context = {
        'course_title': course_title,
        'course_url': course_url,
        'course_image_url': image_url,
        'account_settings_url': 'https://{}{}'.format(settings.SITE_NAME, reverse('dashboard')),
        'platform_name': settings.PLATFORM_NAME,
    }
    return email_context
Пример #29
0
def courses(request):
    """
    Render "find courses" page.  The course selection work is done in courseware.courses.
    """
    courses = sort_by_announcement(get_courses(request.user, request.META.get('HTTP_HOST')))
    course_list = []
    for course in courses:
        course_item = {
            "display_number": course.display_number_with_default,
            "course_title": get_course_about_section(course, 'title'),
            "course_description": get_course_about_section(course, 'short_description'),
            "display_organization": get_course_about_section(course, 'university'),
            "course_image_url": course_image_url(course),
            "course_start": course.start,
            "course_id": course.id.to_deprecated_string(),
        }
        course_list.append(course_item)

    return JsonResponse(course_list)
Пример #30
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id.to_deprecated_string()
    course_title = course.display_name
    course_end_date = get_default_time_display(course.end)
    course_url = 'https://{}{}'.format(
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id})
    )
    image_url = u'https://{}{}'.format(settings.SITE_NAME, course_image_url(course))
    email_context = {
        'course_title': course_title,
        'course_url': course_url,
        'course_image_url': image_url,
        'course_end_date': course_end_date,
        'account_settings_url': 'https://{}{}'.format(settings.SITE_NAME, reverse('account_settings')),
        'platform_name': settings.PLATFORM_NAME,
    }
    return email_context
Пример #31
0
def get_course_enrollment(request):
    if not request.user.is_authenticated():
        return JsonResponse({ "status": False })

    # for microsites, we want to filter and only show enrollments for courses
    # within the microsites 'ORG'
    course_org_filter = microsite.get_value('course_org_filter')

    # Let's filter out any courses in an "org" that has been declared to be
    # in a Microsite
    org_filter_out_set = microsite.get_all_orgs()

    # remove our current Microsite from the "filter out" list, if applicable
    if course_org_filter:
        org_filter_out_set.remove(course_org_filter)

    # Build our (course, enrollment) list for the user, but ignore any courses
    # that no longer exist (because the course IDs have changed). Still, we don't
    # delete those enrollments, because it could have been a data push snafu.
    course_enrollment_pairs = list(get_course_enrollment_pairs(request.user, course_org_filter, org_filter_out_set))

    enrollment_list = []
    for course, enrollment in course_enrollment_pairs:
        item = {
            "course_image_url": course_image_url(course),
            "course_id": course.id.to_deprecated_string(),
            "display_organization": get_course_about_section(course, 'university'),
            "display_number": course.display_number_with_default,
            "display_name": course.display_name_with_default,
            "course_start": course.start,
            "course_end": course.end,
            "enrollment_start": course.enrollment_start,
            "enrollment_end": course.enrollment_end,
            "advertised_start": course.advertised_start,
            "enrollment_date": enrollment.created,
            "active": enrollment.is_active,
        }
    enrollment_list.append(item)
    
    return JsonResponse({ "status": True, "enrollment": enrollment_list })
Пример #32
0
def mobi_course_info(request, course, action=None):
    course_logo = course_image_url(course)
    host = request.get_host()

    try:
        user = request.user
    except:
        user = AnonymousUser()

    result = {
        "id": course.id.replace('/', '.'),
        "name": course.display_name_with_default,
        "logo": host + course_logo,
        "org": course.display_org_with_default,
        "course_number": course.display_number_with_default,
        "start_date": course.start.strftime("%Y-%m-%d"),
        "course_category": course.course_category,
        "course_level": course.course_level,
        "registered": registered_for_course(course, user),
        "about": get_course_about_section(course, 'short_description'),
        "category": course.category,
        "course_price": course.display_course_price_with_default
    }

    def compute_action_imgurl(imgname):
        course_mini_info = course.id.split('/')
        asset_location = StaticContent.compute_location(course_mini_info[0], course_mini_info[1], imgname)

        return host + StaticContent.get_url_path_from_location(asset_location)


    for imgname in ['mobi', 'mobi_r', 'ott_r']:
        try:
            result[imgname] = compute_action_imgurl(imgname + '_logo.jpg')
        except:
            result[imgname] = host + course_logo

    return result
Пример #33
0
def mobi_course_info(request, course, action=None):
    course_logo = course_image_url(course)
    host = request.get_host()

    try:
        user = request.user
    except:
        user = AnonymousUser()

    result = {
        "id": course.id.replace('/', '.'),
        "name": course.display_name_with_default,
        "logo": host + course_logo,
        "org": course.display_org_with_default,
        "course_number": course.display_number_with_default,
        "start_date": course.start.strftime("%Y-%m-%d"),
        "course_category": course.course_category,
        "course_level": course.course_level,
        "registered": registered_for_course(course, user),
        "about": get_course_about_section(course, 'short_description'),
        "category": course.category,
        "course_price": course.display_course_price_with_default
    }

    def compute_action_imgurl(imgname):
        course_mini_info = course.id.split('/')
        asset_location = StaticContent.compute_location(
            course_mini_info[0], course_mini_info[1], imgname)

        return host + StaticContent.get_url_path_from_location(asset_location)

    for imgname in ['mobi', 'mobi_r', 'ott_r']:
        try:
            result[imgname] = compute_action_imgurl(imgname + '_logo.jpg')
        except:
            result[imgname] = host + course_logo

    return result
Пример #34
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id.to_deprecated_string()
    course_title = course.display_name
    course_end_date = get_default_time_display(course.end)
    scheme = u"https" if settings.HTTPS == "on" else u"http"
    course_url = '{}://{}{}'.format(
        scheme,
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id})
    )
    image_url = u'{}://{}{}'.format(scheme, settings.SITE_NAME, course_image_url(course))
    email_context = {
        'course_title': course_title,
        'course_url': course_url,
        'course_image_url': image_url,
        'course_end_date': course_end_date,
        'account_settings_url': '{}://{}{}'.format(scheme, settings.SITE_NAME, reverse('account_settings')),
        'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME),
    }
    return email_context
Пример #35
0
def json_courses(request,courses):
    c_list=[]
    for c in courses:
        m_list=[]
        img_url=course_image_url(c)
        short_disc=get_course_about_section(c, 'short_description')
        about_url=reverse('about_course', args=[c.id.to_deprecated_string()])
        m_list.append(c.id.to_deprecated_string())
        m_list.append(c.is_newish)
        m_list.append(c.display_number_with_default)
        m_list.append(c.display_name_with_default)
        m_list.append(c.display_org_with_default)
        m_list.append(c.start_date_is_still_default)
        m_list.append(c.start_date_text)
        m_list.append(img_url)
        m_list.append(short_disc)
        m_list.append(about_url)
        m_list.append(len(courses))
        c_list.append(m_list)
		
    json_list=json.dumps([{'id': a, 'is_new':b, 'number':n, 'name':m, 'org':o, 'start_date_is_still':d,'start_date_text':s,'img_url':i,'short_disc':di,'about_url':ab,'lenth':l} for a,b,n,m,o,d,s,i,di,ab,l in c_list])
    
    return json_list
Пример #36
0
    def to_native(self, course):
        course_id = unicode(course.id)
        request = self.context.get('request', None)
        if request:
            video_outline_url = reverse('video-summary-list',
                                        kwargs={'course_id': course_id},
                                        request=request)
            course_updates_url = reverse('course-updates-list',
                                         kwargs={'course_id': course_id},
                                         request=request)
            course_handouts_url = reverse('course-handouts-list',
                                          kwargs={'course_id': course_id},
                                          request=request)
        else:
            video_outline_url = None
            course_updates_url = None
            course_handouts_url = None

        return {
            "id": course_id,
            "name": course.display_name,
            "number": course.display_number_with_default,
            "org": course.display_org_with_default,
            "start": course.start,
            "end": course.end,
            "course_image": course_image_url(course),
            "social_urls": {
                "facebook": course.facebook_url,
            },
            "latest_updates": {
                "video": None
            },
            "video_outline": video_outline_url,
            "course_updates": course_updates_url,
            "course_handouts": course_handouts_url,
            "subscription_id": course.clean_id(padding_char='_'),
        }
Пример #37
0
def _get_course_email_context(course):
    """
    Returns context arguments to apply to all emails, independent of recipient.
    """
    course_id = course.id
    course_title = course.display_name
    course_url = "http://{}{}".format(settings.SITE_NAME, reverse("course_root", kwargs={"course_id": course_id}))
    course_about_url = "http://" + settings.SITE_NAME + "/courses/" + course_id + "/about"
    image_url = "http://{}{}".format(settings.SITE_NAME, course_image_url(course))

    if settings.SITE_NAME.startswith("http://"):
        image_url = image_url[7:]
        course_about_url = course_about_url[7:]

    email_context = {
        "course_title": course_title,
        "course_url": course_url,
        "course_url_about": course_about_url,
        "course_image_url": image_url,
        "account_settings_url": "https://{}{}".format(settings.SITE_NAME, reverse("dashboard")),
        "platform_name": settings.PLATFORM_NAME,
        "temp_str": u"访问课程请点击",
    }
    return email_context
Пример #38
0
def _update_course_context(request, context, course, platform_name):
    """
    Updates context dictionary with course info.
    """
    context['full_course_image_url'] = request.build_absolute_uri(course_image_url(course))
    course_title_from_cert = context['certificate_data'].get('course_title', '')
    accomplishment_copy_course_name = course_title_from_cert if course_title_from_cert else course.display_name
    context['accomplishment_copy_course_name'] = accomplishment_copy_course_name
    course_number = course.display_coursenumber if course.display_coursenumber else course.number
    context['course_number'] = course_number
    if context['organization_long_name']:
        # Translators:  This text represents the description of course
        context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_short_name}, '
                                                              'an online learning initiative of {partner_long_name} '
                                                              'through {platform_name}.').format(
            partner_short_name=context['organization_short_name'],
            partner_long_name=context['organization_long_name'],
            platform_name=platform_name)
    else:
        # Translators:  This text represents the description of course
        context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_short_name}, '
                                                              'through {platform_name}.').format(
            partner_short_name=context['organization_short_name'],
            platform_name=platform_name)
Пример #39
0
 def get_image_url(self, course):
     """ Get the course image URL """
     return course_image_url(course)
Пример #40
0
 def test_get_image_url(self):
     """Test image URL formatting."""
     course = CourseFactory.create(org='edX', course='999')
     self.assertEquals(course_image_url(course), '/c4x/edX/999/asset/{0}'.format(course.course_image))
Пример #41
0
 def test_spaces_in_image_name(self):
     course = self.process_xml(xml.CourseFactory.build(course_image=u'before after.jpg'))
     self.assertEquals(course_image_url(course), u'/static/xml_test_course/before after.jpg')
Пример #42
0
 def test_non_ascii_image_name(self):
     course = self.process_xml(xml.CourseFactory.build(course_image=u'before_\N{SNOWMAN}_after.jpg'))
     self.assertEquals(course_image_url(course), u'/static/xml_test_course/before_\N{SNOWMAN}_after.jpg')
Пример #43
0
 def test_get_image_url(self):
     """Test image URL formatting."""
     course = self.process_xml(xml.CourseFactory.build())
     self.assertEquals(course_image_url(course), '/static/xml_test_course/images/course_image.jpg')
Пример #44
0
def mobi_forum_course_list(request):
    '''
    get all course what user has talked about
    '''
    nr_transaction = newrelic.agent.current_transaction()
    user = request.user
    course_org_filter = microsite.get_value('course_org_filter')

    # Let's filter out any courses in an "org" that has been declared to be
    # in a Microsite
    org_filter_out_set = microsite.get_all_orgs()

    # remove our current Microsite from the "filter out" list, if applicable
    if course_org_filter:
        org_filter_out_set.remove(course_org_filter)

    # Build our (course, enrollment) list for the user, but ignore any courses that no
    # longer exist (because the course IDs have changed). Still, we don't delete those
    # enrollments, because it could have been a data push snafu.
    course_enrollment_pairs = list(
        get_course_enrollment_pairs(user, course_org_filter,
                                    org_filter_out_set))

    show_courseware_links_for = frozenset(
        course.id for course, _enrollment in course_enrollment_pairs
        if has_access(request.user, course, 'load'))
    user_info = cc.User.from_django_user(request.user).to_dict()
    courselist = []
    for course_id in show_courseware_links_for:
        try:
            user_id = user.id
            profiled_user = cc.User(id=user_id, course_id=course_id)

            query_params = {
                'page': request.GET.get('page', 1),
                'per_page':
                THREADS_PER_PAGE,  # more than threads_per_page to show more activities
            }

            threads, page, num_pages = profiled_user.active_threads(
                query_params)
            query_params['page'] = page
            query_params['num_pages'] = num_pages

            with newrelic.agent.FunctionTrace(nr_transaction,
                                              "get_metadata_for_threads"):
                annotated_content_info = utils.get_metadata_for_threads(
                    course_id, threads, request.user, user_info)
            if annotated_content_info:
                courselist.append(course_id)
        except User.DoesNotExist:
            raise Http404
    course_list = []
    for newcourse in courselist:
        course = course_from_id(newcourse)
        courseid = course.id.replace('/', '.')
        newdict = {
            'imageurl': request.get_host() + course_image_url(course),
            'id': courseid,
            'name': course.display_name
        }
        course_list.append(newdict)

    return JsonResponse({"course-list": course_list})
Пример #45
0
def delegate_email_batches(email_id, user_id):
    """
    Delegates emails by querying for the list of recipients who should
    get the mail, chopping up into batches of settings.EMAILS_PER_TASK size,
    and queueing up worker jobs.

    Returns the number of batches (workers) kicked off.
    """
    try:
        email_obj = CourseEmail.objects.get(id=email_id)
    except CourseEmail.DoesNotExist as exc:
        # The retry behavior here is necessary because of a race condition between the commit of the transaction
        # that creates this CourseEmail row and the celery pipeline that starts this task.
        # We might possibly want to move the blocking into the view function rather than have it in this task.
        log.warning("Failed to get CourseEmail with id %s, retry %d", email_id,
                    current_task.request.retries)
        raise delegate_email_batches.retry(arg=[email_id, user_id], exc=exc)

    to_option = email_obj.to_option
    course_id = email_obj.course_id

    try:
        course = get_course_by_id(course_id, depth=1)
    except Http404 as exc:
        log.exception("get_course_by_id failed: %s", exc.args[0])
        raise Exception("get_course_by_id failed: " + exc.args[0])

    course_url = 'https://{}{}'.format(
        settings.SITE_NAME,
        reverse('course_root', kwargs={'course_id': course_id}))
    image_url = 'https://{}{}'.format(settings.SITE_NAME,
                                      course_image_url(course))

    if to_option == SEND_TO_MYSELF:
        recipient_qset = User.objects.filter(id=user_id)
    elif to_option == SEND_TO_ALL or to_option == SEND_TO_STAFF:
        staff_grpname = _course_staff_group_name(course.location)
        staff_group, _ = Group.objects.get_or_create(name=staff_grpname)
        staff_qset = staff_group.user_set.all()
        instructor_grpname = _course_instructor_group_name(course.location)
        instructor_group, _ = Group.objects.get_or_create(
            name=instructor_grpname)
        instructor_qset = instructor_group.user_set.all()
        recipient_qset = staff_qset | instructor_qset

        if to_option == SEND_TO_ALL:
            enrollment_qset = User.objects.filter(
                courseenrollment__course_id=course_id,
                courseenrollment__is_active=True)
            recipient_qset = recipient_qset | enrollment_qset
        recipient_qset = recipient_qset.distinct()
    else:
        log.error("Unexpected bulk email TO_OPTION found: %s", to_option)
        raise Exception(
            "Unexpected bulk email TO_OPTION found: {0}".format(to_option))

    recipient_qset = recipient_qset.order_by('pk')
    total_num_emails = recipient_qset.count()
    num_queries = int(
        math.ceil(float(total_num_emails) / float(settings.EMAILS_PER_QUERY)))
    last_pk = recipient_qset[0].pk - 1
    num_workers = 0
    for _ in range(num_queries):
        recipient_sublist = list(
            recipient_qset.order_by('pk').filter(pk__gt=last_pk).values(
                'profile__name', 'email', 'pk')[:settings.EMAILS_PER_QUERY])
        last_pk = recipient_sublist[-1]['pk']
        num_emails_this_query = len(recipient_sublist)
        num_tasks_this_query = int(
            math.ceil(
                float(num_emails_this_query) /
                float(settings.EMAILS_PER_TASK)))
        chunk = int(
            math.ceil(
                float(num_emails_this_query) / float(num_tasks_this_query)))
        for i in range(num_tasks_this_query):
            to_list = recipient_sublist[i * chunk:i * chunk + chunk]
            course_email.delay(email_id, to_list, course.display_name,
                               course_url, image_url, False)
        num_workers += num_tasks_this_query
    return num_workers
Пример #46
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified student's certificate
    If a certificate is not available, we display a "Sorry!" screen instead
    """

    # Create the initial view context, bootstrapping with Django settings and passed-in values
    context = {}
    context['platform_name'] = microsite.get_value("platform_name", settings.PLATFORM_NAME)
    context['course_id'] = course_id
    preview_mode = request.GET.get('preview', None)

    # Update the view context with the default ConfigurationModel settings
    configuration = CertificateHtmlViewConfiguration.get_config()
    # if we are in a microsite, then let's first see if there is an override
    # section in our config
    config_key = microsite.get_value('microsite_config_key', 'default')
    # if there is no special microsite override, then let's use default
    if config_key not in configuration:
        config_key = 'default'
    context.update(configuration.get(config_key, {}))

    # Translators:  'All rights reserved' is a legal term used in copyrighting to protect published content
    reserved = _("All rights reserved")
    context['copyright_text'] = '&copy; {year} {platform_name}. {reserved}.'.format(
        year=settings.COPYRIGHT_YEAR,
        platform_name=context.get('platform_name'),
        reserved=reserved
    )

    # Translators:  This text is bound to the HTML 'title' element of the page and appears
    # in the browser title bar when a requested certificate is not found or recognized
    context['document_title'] = _("Invalid Certificate")

    # Translators: The &amp; characters represent an ampersand character and can be ignored
    context['company_tos_urltext'] = _("Terms of Service &amp; Honor Code")

    # Translators: A 'Privacy Policy' is a legal document/statement describing a website's use of personal information
    context['company_privacy_urltext'] = _("Privacy Policy")

    # Translators: This line appears as a byline to a header image and describes the purpose of the page
    context['logo_subtitle'] = _("Certificate Validation")
    invalid_template_path = 'certificates/invalid.html'

    # Kick the user back to the "Invalid" screen if the feature is disabled
    if not has_html_certificates_enabled(course_id):
        return render_to_response(invalid_template_path, context)

    # Load the core building blocks for the view context
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = modulestore().get_course(course_key)

        if not course:
            raise CourseDoesNotExist

        # Attempt to load the user's generated certificate data
        if preview_mode:
            user_certificate = GeneratedCertificate.objects.get(
                user=user,
                course_id=course_key,
                mode=preview_mode
            )
        else:
            user_certificate = GeneratedCertificate.objects.get(
                user=user,
                course_id=course_key
            )

    # If there's no generated certificate data for this user, we need to see if we're in 'preview' mode...
    # If we are, we'll need to create a mock version of the user_certificate container for previewing
    except GeneratedCertificate.DoesNotExist:
        if preview_mode and (
            has_access(request.user, 'instructor', course)
            or has_access(request.user, 'staff', course)
        ):
            user_certificate = GeneratedCertificate(
                mode=preview_mode,
                verify_uuid=unicode(uuid4().hex),
                modified_date=datetime.now().date()
            )
        else:
            return render_to_response(invalid_template_path, context)

    # For any other expected exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, CourseDoesNotExist, User.DoesNotExist):
        return render_to_response(invalid_template_path, context)

    # Badge Request Event Tracking Logic
    if 'evidence_visit' in request.GET:
        try:
            badge = BadgeAssertion.objects.get(user=user, course_id=course_key)
            tracker.emit(
                'edx.badge.assertion.evidence_visited',
                {
                    'user_id': user.id,
                    'course_id': unicode(course_key),
                    'enrollment_mode': badge.mode,
                    'assertion_id': badge.id,
                    'assertion_image_url': badge.data['image'],
                    'assertion_json_url': badge.data['json']['id'],
                    'issuer': badge.data['issuer'],
                }
            )
        except BadgeAssertion.DoesNotExist:
            log.warn(
                "Could not find badge for %s on course %s.",
                user.id,
                course_key,
            )

    # Okay, now we have all of the pieces, time to put everything together

    # Get the active certificate configuration for this course
    # If we do not have an active certificate, we'll need to send the user to the "Invalid" screen
    # Passing in the 'preview' parameter, if specified, will return a configuration, if defined
    active_configuration = get_active_web_certificate(course, preview_mode)
    if active_configuration is None:
        return render_to_response(invalid_template_path, context)
    else:
        context['certificate_data'] = active_configuration

    # Append/Override the existing view context values with any mode-specific ConfigurationModel values
    context.update(configuration.get(user_certificate.mode, {}))

    # Append/Override the existing view context values with request-time values
    _update_certificate_context(context, course, user, user_certificate)
    share_url = request.build_absolute_uri(
        reverse(
            'certificates:html_view',
            kwargs=dict(user_id=str(user_id), course_id=unicode(course_id))
        )
    )
    context['share_url'] = share_url
    twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format(
        twitter_share_text=context['twitter_share_text'],
        share_url=urllib.quote_plus(share_url)
    )
    context['twitter_url'] = twitter_url
    context['full_course_image_url'] = request.build_absolute_uri(course_image_url(course))

    # If enabled, show the LinkedIn "add to profile" button
    # Clicking this button sends the user to LinkedIn where they
    # can add the certificate information to their profile.
    linkedin_config = LinkedInAddToProfileConfiguration.current()
    if linkedin_config.enabled:
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id,
            course.display_name,
            user_certificate.mode,
            request.build_absolute_uri(get_certificate_url(
                user_id=user.id,
                course_id=unicode(course.id)
            ))
        )
    else:
        context['linked_in_url'] = None

    # Microsites will need to be able to override any hard coded
    # content that was put into the context in the
    # _update_certificate_context() call above. For example the
    # 'company_about_description' talks about edX, which we most likely
    # do not want to keep in a microsite
    #
    # So we need to re-apply any configuration/content that
    # we are sourceing from the database. This is somewhat duplicative of
    # the code at the beginning of this method, but we
    # need the configuration at the top as some error code paths
    # require that to be set up early on in the pipeline
    #
    microsite_config_key = microsite.get_value('microsite_config_key')
    if microsite_config_key:
        context.update(configuration.get(microsite_config_key, {}))

    # track certificate evidence_visited event for analytics when certificate_user and accessing_user are different
    if request.user and request.user.id != user.id:
        emit_certificate_event('evidence_visited', user, course_id, course, {
            'certificate_id': user_certificate.verify_uuid,
            'enrollment_mode': user_certificate.mode,
            'social_network': CertificateSocialNetworks.linkedin
        })

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # FINALLY, generate and send the output the client
    if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False):
        custom_template = get_certificate_template(course_key, user_certificate.mode)
        if custom_template:
            template = Template(custom_template)
            context = RequestContext(request, context)
            return HttpResponse(template.render(context))

    return render_to_response("certificates/valid.html", context)
Пример #47
0
 def test_get_image_url(self):
     """Test image URL formatting."""
     course = self.process_xml(xml.CourseFactory.build())
     self.assertEquals(course_image_url(course),
                       '/static/xml_test_course/images/course_image.jpg')
Пример #48
0
def _update_certificate_context(context, course, user, user_certificate):
    """
    Build up the certificate web view context using the provided values
    (Helper method to keep the view clean)
    """
    # Populate dynamic output values using the course/certificate data loaded above
    user_fullname = user.profile.name
    platform_name = microsite.get_value("platform_name",
                                        settings.PLATFORM_NAME)
    certificate_type = context.get('certificate_type')

    context['username'] = user.username
    context['course_mode'] = user_certificate.mode
    context['accomplishment_user_id'] = user.id
    context['accomplishment_copy_name'] = user_fullname
    context['accomplishment_copy_username'] = user.username
    context['accomplishment_copy_course_org'] = course.org
    context['accomplishment_copy_course_name'] = course.display_name
    context['course_image_url'] = course_image_url(course)
    context['share_settings'] = settings.FEATURES.get(
        'SOCIAL_SHARING_SETTINGS', {})
    try:
        badge = BadgeAssertion.objects.get(
            user=user, course_id=course.location.course_key)
    except BadgeAssertion.DoesNotExist:
        badge = None
    context['badge'] = badge

    # Override the defaults with any mode-specific static values
    context['certificate_id_number'] = user_certificate.verify_uuid
    context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format(
        prefix=context.get('certificate_verify_url_prefix'),
        uuid=user_certificate.verify_uuid,
        suffix=context.get('certificate_verify_url_suffix'))

    # Translators:  The format of the date includes the full name of the month
    context['certificate_date_issued'] = _('{month} {day}, {year}').format(
        month=user_certificate.modified_date.strftime("%B"),
        day=user_certificate.modified_date.day,
        year=user_certificate.modified_date.year)

    accd_course_org_html = '<span class="detail--xuniversity">{partner_name}</span>'.format(
        partner_name=course.org)
    accd_platform_name_html = '<span class="detail--company">{platform_name}</span>'.format(
        platform_name=platform_name)
    # Translators: This line appears on the certificate after the name of a course, and provides more
    # information about the organizations providing the course material to platform users
    context['accomplishment_copy_course_description'] = _(
        'a course of study offered by {partner_name}, '
        'through {platform_name}.').format(
            partner_name=accd_course_org_html,
            platform_name=accd_platform_name_html)

    # Translators: Accomplishments describe the awards/certifications obtained by students on this platform
    context['accomplishment_copy_about'] = _(
        'About {platform_name} Accomplishments').format(
            platform_name=platform_name)

    context['accomplishment_more_title'] = _(
        "More Information About {user_name}'s Certificate:").format(
            user_name=user_fullname)

    # Translators:  This line appears on the page just before the generation date for the certificate
    context['certificate_date_issued_title'] = _("Issued On:")

    # Translators:  The Certificate ID Number is an alphanumeric value unique to each individual certificate
    context['certificate_id_number_title'] = _('Certificate ID Number')

    context['certificate_info_title'] = _('About {platform_name} Certificates'
                                          ).format(platform_name=platform_name)

    # Translators: This text describes the purpose (and therefore, value) of a course certificate
    # 'verifying your identity' refers to the process for establishing the authenticity of the student
    context['certificate_info_description'] = _(
        "{platform_name} acknowledges achievements through certificates, which "
        "are awarded for various activities {platform_name} students complete "
        "under the <a href='{tos_url}'>{platform_name} Honor Code</a>.  Some "
        "certificates require completing additional steps, such as "
        "<a href='{verified_cert_url}'> verifying your identity</a>.").format(
            platform_name=platform_name,
            tos_url=context.get('company_tos_url'),
            verified_cert_url=context.get('company_verified_certificate_url'))

    context['certificate_verify_title'] = _(
        "How {platform_name} Validates Student Certificates").format(
            platform_name=platform_name)

    # Translators:  This text describes the validation mechanism for a certificate file (known as GPG security)
    context['certificate_verify_description'] = _(
        'Certificates issued by {platform_name} are signed by a gpg key so '
        'that they can be validated independently by anyone with the '
        '{platform_name} public key. For independent verification, '
        '{platform_name} uses what is called a '
        '"detached signature"&quot;".').format(platform_name=platform_name)

    context['certificate_verify_urltext'] = _(
        "Validate this certificate for yourself")

    # Translators:  This text describes (at a high level) the mission and charter the edX platform and organization
    context['company_about_description'] = _(
        "{platform_name} offers interactive online classes and MOOCs from the "
        "world's best universities, including MIT, Harvard, Berkeley, University "
        "of Texas, and many others.  {platform_name} is a non-profit online "
        "initiative created by founding partners Harvard and MIT.").format(
            platform_name=platform_name)

    context['company_about_title'] = _("About {platform_name}").format(
        platform_name=platform_name)

    context['company_about_urltext'] = _(
        "Learn more about {platform_name}").format(platform_name=platform_name)

    context['company_courselist_urltext'] = _(
        "Learn with {platform_name}").format(platform_name=platform_name)

    context['company_careers_urltext'] = _("Work at {platform_name}").format(
        platform_name=platform_name)

    context['company_contact_urltext'] = _("Contact {platform_name}").format(
        platform_name=platform_name)

    # Translators:  This text appears near the top of the certficate and describes the guarantee provided by edX
    context['document_banner'] = _(
        "{platform_name} acknowledges the following student accomplishment"
    ).format(platform_name=platform_name)

    # Translators:  This text represents the verification of the certificate
    context['document_meta_description'] = _(
        'This is a valid {platform_name} certificate for {user_name}, '
        'who participated in {partner_name} {course_number}').format(
            platform_name=platform_name,
            user_name=user_fullname,
            partner_name=course.org,
            course_number=course.number)

    # Translators:  This text is bound to the HTML 'title' element of the page and appears in the browser title bar
    context['document_title'] = _(
        "{partner_name} {course_number} Certificate | {platform_name}").format(
            partner_name=course.org,
            course_number=course.number,
            platform_name=platform_name)

    # Translators:  This text fragment appears after the student's name (displayed in a large font) on the certificate
    # screen.  The text describes the accomplishment represented by the certificate information displayed to the user
    context['accomplishment_copy_description_full'] = _(
        "successfully completed, received a passing grade, and was "
        "awarded a {platform_name} {certificate_type} "
        "Certificate of Completion in ").format(
            platform_name=platform_name,
            certificate_type=context.get("certificate_type"))

    certificate_type_description = get_certificate_description(
        user_certificate.mode, certificate_type, platform_name)
    if certificate_type_description:
        context['certificate_type_description'] = certificate_type_description

    # If enabled, show the LinkedIn "add to profile" button
    # Clicking this button sends the user to LinkedIn where they
    # can add the certificate information to their profile.
    linkedin_config = LinkedInAddToProfileConfiguration.current()
    if linkedin_config.enabled:
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id, course.display_name, user_certificate.mode,
            get_certificate_url(user_id=user.id,
                                course_id=unicode(course.id),
                                verify_uuid=user_certificate.verify_uuid))

    # Translators: This line is displayed to a user who has completed a course and achieved a certification
    context['accomplishment_banner_opening'] = _(
        "{fullname}, you've earned a certificate!").format(
            fullname=user_fullname)

    # Translators: This line congratulates the user and instructs them to share their accomplishment on social networks
    context['accomplishment_banner_congrats'] = _(
        "Congratulations! This page summarizes all of the details of what "
        "you've accomplished. Show it off to family, friends, and colleagues "
        "in your social and professional networks.")

    # Translators: This line leads the reader to understand more about the certificate that a student has been awarded
    context['accomplishment_copy_more_about'] = _(
        "More about {fullname}'s accomplishment").format(
            fullname=user_fullname)
Пример #49
0
 def test_spaces_in_image_name(self):
     course = self.process_xml(
         xml.CourseFactory.build(course_image=u'before after.jpg'))
     self.assertEquals(course_image_url(course),
                       u'/static/xml_test_course/before after.jpg')
Пример #50
0
def _update_certificate_context(context, course, user, user_certificate):
    """
    Build up the certificate web view context using the provided values
    (Helper method to keep the view clean)
    """
    # Populate dynamic output values using the course/certificate data loaded above
    user_fullname = user.profile.name
    platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME)
    certificate_type = context.get('certificate_type')
    partner_short_name = course.org
    partner_long_name = None
    organizations = organization_api.get_course_organizations(course_id=course.id)
    if organizations:
        #TODO Need to add support for multiple organizations, Currently we are interested in the first one.
        organization = organizations[0]
        partner_long_name = organization.get('name', partner_long_name)
        partner_short_name = organization.get('short_name', partner_short_name)
        context['organization_long_name'] = partner_long_name
        context['organization_short_name'] = partner_short_name
        context['organization_logo'] = organization.get('logo', None)

    context['username'] = user.username
    context['course_mode'] = user_certificate.mode
    context['accomplishment_user_id'] = user.id
    context['accomplishment_copy_name'] = user_fullname
    context['accomplishment_copy_username'] = user.username
    context['accomplishment_copy_course_org'] = partner_short_name
    context['accomplishment_copy_course_name'] = course.display_name
    context['course_image_url'] = course_image_url(course)
    context['share_settings'] = settings.FEATURES.get('SOCIAL_SHARING_SETTINGS', {})
    context['course_number'] = course.number
    try:
        badge = BadgeAssertion.objects.get(user=user, course_id=course.location.course_key)
    except BadgeAssertion.DoesNotExist:
        badge = None
    context['badge'] = badge

    # Override the defaults with any mode-specific static values
    context['certificate_id_number'] = user_certificate.verify_uuid
    context['certificate_verify_url'] = "{prefix}{uuid}{suffix}".format(
        prefix=context.get('certificate_verify_url_prefix'),
        uuid=user_certificate.verify_uuid,
        suffix=context.get('certificate_verify_url_suffix')
    )

    # Translators:  The format of the date includes the full name of the month
    context['certificate_date_issued'] = _('{month} {day}, {year}').format(
        month=user_certificate.modified_date.strftime("%B"),
        day=user_certificate.modified_date.day,
        year=user_certificate.modified_date.year
    )

    if partner_long_name:
        context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_short_name}, an '
                                                              'online learning initiative of {partner_long_name} '
                                                              'through {platform_name}.').format(
            partner_short_name=partner_short_name,
            partner_long_name=partner_long_name,
            platform_name=platform_name
        )
    else:
        context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_short_name}, '
                                                              'through {platform_name}.').format(
            partner_short_name=partner_short_name,
            platform_name=platform_name
        )

    # Translators: Accomplishments describe the awards/certifications obtained by students on this platform
    context['accomplishment_copy_about'] = _('About {platform_name} Accomplishments').format(
        platform_name=platform_name
    )

    context['accomplishment_more_title'] = _("More Information About {user_name}'s Certificate:").format(
        user_name=user_fullname
    )

    # Translators:  This line appears on the page just before the generation date for the certificate
    context['certificate_date_issued_title'] = _("Issued On:")

    # Translators:  The Certificate ID Number is an alphanumeric value unique to each individual certificate
    context['certificate_id_number_title'] = _('Certificate ID Number')

    context['certificate_info_title'] = _('About {platform_name} Certificates').format(
        platform_name=platform_name
    )

    # Translators: This text describes the purpose (and therefore, value) of a course certificate
    # 'verifying your identity' refers to the process for establishing the authenticity of the student
    context['certificate_info_description'] = _("{platform_name} acknowledges achievements through certificates, which "
                                                "are awarded for various activities {platform_name} students complete "
                                                "under the <a href='{tos_url}'>{platform_name} Honor Code</a>.  Some "
                                                "certificates require completing additional steps, such as "
                                                "<a href='{verified_cert_url}'> verifying your identity</a>.").format(
        platform_name=platform_name,
        tos_url=context.get('company_tos_url'),
        verified_cert_url=context.get('company_verified_certificate_url')
    )

    context['certificate_verify_title'] = _("How {platform_name} Validates Student Certificates").format(
        platform_name=platform_name
    )

    # Translators:  This text describes the validation mechanism for a certificate file (known as GPG security)
    context['certificate_verify_description'] = _('Certificates issued by {platform_name} are signed by a gpg key so '
                                                  'that they can be validated independently by anyone with the '
                                                  '{platform_name} public key. For independent verification, '
                                                  '{platform_name} uses what is called a '
                                                  '"detached signature"&quot;".').format(platform_name=platform_name)

    context['certificate_verify_urltext'] = _("Validate this certificate for yourself")

    # Translators:  This text describes (at a high level) the mission and charter the edX platform and organization
    context['company_about_description'] = _("{platform_name} offers interactive online classes and MOOCs from the "
                                             "world's best universities, including MIT, Harvard, Berkeley, University "
                                             "of Texas, and many others.  {platform_name} is a non-profit online "
                                             "initiative created by founding partners Harvard and MIT.").format(
        platform_name=platform_name
    )

    context['company_about_title'] = _("About {platform_name}").format(platform_name=platform_name)

    context['company_about_urltext'] = _("Learn more about {platform_name}").format(platform_name=platform_name)

    context['company_courselist_urltext'] = _("Learn with {platform_name}").format(platform_name=platform_name)

    context['company_careers_urltext'] = _("Work at {platform_name}").format(platform_name=platform_name)

    context['company_contact_urltext'] = _("Contact {platform_name}").format(platform_name=platform_name)

    # Translators:  This text appears near the top of the certficate and describes the guarantee provided by edX
    context['document_banner'] = _("{platform_name} acknowledges the following student accomplishment").format(
        platform_name=platform_name
    )

    # Translators:  This text represents the verification of the certificate
    context['document_meta_description'] = _('This is a valid {platform_name} certificate for {user_name}, '
                                             'who participated in {partner_short_name} {course_number}').format(
        platform_name=platform_name,
        user_name=user_fullname,
        partner_short_name=partner_short_name,
        course_number=course.number
    )

    # Translators:  This text is bound to the HTML 'title' element of the page and appears in the browser title bar
    context['document_title'] = _("{partner_short_name} {course_number} Certificate | {platform_name}").format(
        partner_short_name=partner_short_name,
        course_number=course.number,
        platform_name=platform_name
    )

    # Translators:  This text fragment appears after the student's name (displayed in a large font) on the certificate
    # screen.  The text describes the accomplishment represented by the certificate information displayed to the user
    context['accomplishment_copy_description_full'] = _("successfully completed, received a passing grade, and was "
                                                        "awarded a {platform_name} {certificate_type} "
                                                        "Certificate of Completion in ").format(
        platform_name=platform_name,
        certificate_type=context.get("certificate_type")
    )

    certificate_type_description = get_certificate_description(user_certificate.mode, certificate_type, platform_name)
    if certificate_type_description:
        context['certificate_type_description'] = certificate_type_description

    # Translators: This line is displayed to a user who has completed a course and achieved a certification
    context['accomplishment_banner_opening'] = _("{fullname}, you've earned a certificate!").format(
        fullname=user_fullname
    )

    # Translators: This line congratulates the user and instructs them to share their accomplishment on social networks
    context['accomplishment_banner_congrats'] = _("Congratulations! This page summarizes all of the details of what "
                                                  "you've accomplished. Show it off to family, friends, and colleagues "
                                                  "in your social and professional networks.")

    # Translators: This line leads the reader to understand more about the certificate that a student has been awarded
    context['accomplishment_copy_more_about'] = _("More about {fullname}'s accomplishment").format(
        fullname=user_fullname
    )
Пример #51
0
 def test_get_image_url(self):
     """Test image URL formatting."""
     course = CourseFactory.create(org='edX', course='999')
     self.assertEquals(course_image_url(course),
                       '/c4x/edX/999/asset/{0}'.format(course.course_image))
def render_body(context,course,**pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(course=course,pageargs=pageargs)
        _import_ns = {}
        _mako_get_namespace(context, '__anon_0x81b7fd0')._populate(_import_ns, [u'stanford_theme_enabled'])
        def format_courseOrg(orgStr):
            return render_format_courseOrg(context.locals_(__M_locals),orgStr)
        __M_writer = context.writer()
        # SOURCE LINE 1
        __M_writer(u'\n')
        # SOURCE LINE 2
        __M_writer(u'\n')
        # SOURCE LINE 3
        __M_writer(u'\n\n<!--@begin:Show wireframes before implementing the functionalities of the page-->\n<!--@date:2013-11-02-->\n<style type="text/css" media="screen">\n  a.btnx:hover {\n  background:#638194;\n  transition-delay: 0s, 0s, 0s;\n  transition-duration: 0.25s, 0.25s, 0.25s;\n  transition-property:color, background,\u200b box-shadow;\n  transition-timing-function:cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1);\n  transition-duration:0.25s,\u200b 0.25s,\u200b 0.25s;\n  color:#fff;\n  }\n  a.btnx {\n  background-color:#556370;\n  text-decoration: none;\n  padding-bottom: 7px;\n  padding-left: 10px;\n  padding-right: 10px;\n  padding-top: 7px;\n  cursor: pointer;\n  font-family: \'Open Sans\',Verdana,Geneva,sans-serif;\n  color:#fff;\n  transition-timing-function:cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1);\n  }\n  a.btnx:normal {\n  background-color:#126F9A;\n  text-decoration: none;\n  cursor: pointer;\n  font-family: \'Open Sans\',Verdana,Geneva,sans-serif;\n  color:#fff;\n  transition-timing-function:cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1), cubic-bezier(0.42, 0, 0.58, 1);\n  }\n  #blocks *{font-family:\'Open Sans\',\u200bArial;}\n  #blocks p{margin-top:10px;}\n/*@begin:tag \'p\' sytle of short_description read from course_overview*/\n/*@date:2013-12-09*/\n  p{line-height:15px;}\n/*@end*/\n</style>\n\n')
        # SOURCE LINE 49
        __M_writer(u'\n')
        # SOURCE LINE 55
        __M_writer(u'\n')
        # SOURCE LINE 62
        __M_writer(u'\n')
        # SOURCE LINE 63
        __M_writer(u'\n<style type="text/css" media="screen">\n  *{font-family: \'Open Sans\'}\n  .course-card{\n    background-color: #FFFFFF;\n    border-radius: 6px;\n    -moz-border-radius: 6px;\n    -webkit-border-radius: 6px;\n    box-shadow: 3px 3px 7px 0px rgba(0,0,0,0.1);\n    float: left;\n    width: 242px;\n    min-height: 242px;\n    margin: 20px;\n    position: relative;\n    cursor: auto!important;\n  }\n  .card-top{position: relative;}\n  .image-style{\n    border-radius: 6px 6px 0px 0px;\n    -moz-border-radius: 6px 6px 0px 0px;\n    -webkit-border-radius: 6px 6px 0px 0px;\n    display: block;\n  }\n  .card-link{\n    display: table-cell;\n    width: 242px;\n    height: 60px;\n    vertical-align: middle;\n    padding: 0 17px;\n    font-size: 22px;\n    color: #FFFFFF;\n    background: rgba(18,111,154,0.95);\n    text-decoration: none!important;\n  }\n  .course-title {\n    display: table;\n    height: 60px;\n    position: absolute;\n    bottom: 0;\n    font-size:14px;\n  }\n</style>\n<script>\n  $(function()\n  {\n    $(".card-link").hover(\n      function () {\n        $(this).find("span").html("<span style=\'margin-right:80px;\'>Course Details</span><span>\u203a</span>");\n      },\n      function () {\n        $(this).find("span").html($(this).attr("title"));\n      });\n      $(".card-link").each(function(){\n        if($(this).height()>60)\n        {\n          $(this).css("fontSize","12px");\n        }\n    });\n  })\n</script>\n\n<div class="course-card" style="cursor:pointer;margin-left:45px;">\n  <div class="card-top">\n    <div><div class="field-items"><figure><img typeof="foaf:Image" class="image-style" src="')
        # SOURCE LINE 126
        __M_writer(filters.decode.utf8(course_image_url(course)))
        __M_writer(u'" width="242" height="150" alt="')
        __M_writer(filters.html_escape(filters.decode.utf8(course.display_number_with_default )))
        __M_writer(u' ')
        __M_writer(filters.decode.utf8(get_course_about_section(course, 'title')))
        __M_writer(u' Cover Image"></figure></div></div>\n    <div class="course-title"><div class="field-content"><a href="')
        # SOURCE LINE 127
        __M_writer(filters.decode.utf8(reverse('cabout', args=[course.id])))
        __M_writer(u'" class="card-link" title="')
        __M_writer(filters.decode.utf8(get_course_about_section(course, 'title')))
        __M_writer(u'"><span>')
        __M_writer(filters.decode.utf8(get_course_about_section(course, 'title')))
        __M_writer(u'</span></a></div></div>  \n  </div>\n    <div class="card-bottom" style="text-align:left;padding:10px 0 0 10px;">\n    <table><tr>\n    <td height="45"><div class="field-content"><span class="course-org" style="font-size:14px;font-weight:bold;color:#146C99">')
        # SOURCE LINE 131
        __M_writer(filters.decode.utf8(format_courseOrg(course.display_organization)))
        __M_writer(u'</span> | <span class="course-number" style="font-size:14px;font-weight:bold;">')
        __M_writer(filters.html_escape(filters.decode.utf8(course.display_number_with_default )))
        __M_writer(u'</span></div>\n    <div class="course-grade" style="font-size:14px;font-weight:bold;margin-top:5px;">')
        # SOURCE LINE 132
        __M_writer(filters.decode.utf8(course.display_grades))
        __M_writer(u'</div></td>\n    <td style="text-align:center;">\n')
        # SOURCE LINE 134
        if course.display_credit:
            # SOURCE LINE 135
            __M_writer(u'      <img src="/static/images/credit.jpg" width="30" height="30" title="Qualifies for Credit"/>\n')
        # SOURCE LINE 137
        __M_writer(u'    </td>\n    </tr>\n    <tr>\n    <td width="190">\n')
        # SOURCE LINE 141
        if course.display_prerequisite:
            # SOURCE LINE 142
            __M_writer(u'        <span style="font-size:12px;">')
            __M_writer(filters.decode.utf8(_("Prerequisite Recommended")))
            __M_writer(u'</span>\n')
        # SOURCE LINE 144
        __M_writer(u'    </td>\n    <td width="40" style="text-align:center;">\n')
        # SOURCE LINE 146
        if course.is_newish:
            # SOURCE LINE 147
            __M_writer(u'        <span style="font-size:10px;background:#99cc33;color:#fff;padding:2px;width:27px;">NEW</span>\n')
        # SOURCE LINE 149
        __M_writer(u'      </td></tr></table>\n</div>\n</div>\n')
        return ''
    finally:
        context.caller_stack._pop_frame()
Пример #53
0
def render_html_view(request, user_id, course_id):
    """
    This public view generates an HTML representation of the specified student's certificate
    If a certificate is not available, we display a "Sorry!" screen instead
    """

    # Create the initial view context, bootstrapping with Django settings and passed-in values
    context = {}
    context['platform_name'] = microsite.get_value("platform_name", settings.PLATFORM_NAME)
    context['course_id'] = course_id
    preview_mode = request.GET.get('preview', None)

    # Update the view context with the default ConfigurationModel settings
    configuration = CertificateHtmlViewConfiguration.get_config()
    # if we are in a microsite, then let's first see if there is an override
    # section in our config
    config_key = microsite.get_value('microsite_config_key', 'default')
    # if there is no special microsite override, then let's use default
    if config_key not in configuration:
        config_key = 'default'
    context.update(configuration.get(config_key, {}))

    # Translators:  'All rights reserved' is a legal term used in copyrighting to protect published content
    reserved = _("All rights reserved")
    context['copyright_text'] = '&copy; {year} {platform_name}. {reserved}.'.format(
        year=settings.COPYRIGHT_YEAR,
        platform_name=context.get('platform_name'),
        reserved=reserved
    )

    # Translators:  This text is bound to the HTML 'title' element of the page and appears
    # in the browser title bar when a requested certificate is not found or recognized
    context['document_title'] = _("Invalid Certificate")

    # Translators: The &amp; characters represent an ampersand character and can be ignored
    context['company_tos_urltext'] = _("Terms of Service &amp; Honor Code")

    # Translators: A 'Privacy Policy' is a legal document/statement describing a website's use of personal information
    context['company_privacy_urltext'] = _("Privacy Policy")

    # Translators: This line appears as a byline to a header image and describes the purpose of the page
    context['logo_subtitle'] = _("Certificate Validation")
    invalid_template_path = 'certificates/invalid.html'

    # Kick the user back to the "Invalid" screen if the feature is disabled
    if not has_html_certificates_enabled(course_id):
        return render_to_response(invalid_template_path, context)

    # Load the core building blocks for the view context
    try:
        course_key = CourseKey.from_string(course_id)
        user = User.objects.get(id=user_id)
        course = modulestore().get_course(course_key)

        if not course:
            raise CourseDoesNotExist

        # Attempt to load the user's generated certificate data
        if preview_mode:
            user_certificate = GeneratedCertificate.objects.get(
                user=user,
                course_id=course_key,
                mode=preview_mode
            )
        else:
            user_certificate = GeneratedCertificate.objects.get(
                user=user,
                course_id=course_key
            )

    # If there's no generated certificate data for this user, we need to see if we're in 'preview' mode...
    # If we are, we'll need to create a mock version of the user_certificate container for previewing
    except GeneratedCertificate.DoesNotExist:
        if preview_mode and (
            has_access(request.user, 'instructor', course)
            or has_access(request.user, 'staff', course)
        ):
            user_certificate = GeneratedCertificate(
                mode=preview_mode,
                verify_uuid=unicode(uuid4().hex),
                modified_date=datetime.now().date()
            )
        else:
            return render_to_response(invalid_template_path, context)

    # For any other expected exceptions, kick the user back to the "Invalid" screen
    except (InvalidKeyError, CourseDoesNotExist, User.DoesNotExist):
        return render_to_response(invalid_template_path, context)

    # Badge Request Event Tracking Logic
    if 'evidence_visit' in request.GET:
        try:
            badge = BadgeAssertion.objects.get(user=user, course_id=course_key)
            tracker.emit(
                'edx.badge.assertion.evidence_visited',
                {
                    'user_id': user.id,
                    'course_id': unicode(course_key),
                    'enrollment_mode': badge.mode,
                    'assertion_id': badge.id,
                    'assertion_image_url': badge.data['image'],
                    'assertion_json_url': badge.data['json']['id'],
                    'issuer': badge.data['issuer'],
                }
            )
        except BadgeAssertion.DoesNotExist:
            log.warn(
                "Could not find badge for %s on course %s.",
                user.id,
                course_key,
            )

    # Okay, now we have all of the pieces, time to put everything together

    # Get the active certificate configuration for this course
    # If we do not have an active certificate, we'll need to send the user to the "Invalid" screen
    # Passing in the 'preview' parameter, if specified, will return a configuration, if defined
    active_configuration = get_active_web_certificate(course, preview_mode)
    if active_configuration is None:
        return render_to_response(invalid_template_path, context)
    else:
        context['certificate_data'] = active_configuration

    # Append/Override the existing view context values with any mode-specific ConfigurationModel values
    context.update(configuration.get(user_certificate.mode, {}))

    # Append/Override the existing view context values with request-time values
    _update_certificate_context(context, course, user, user_certificate)
    share_url = request.build_absolute_uri(
        reverse(
            'certificates:html_view',
            kwargs=dict(user_id=str(user_id), course_id=unicode(course_id))
        )
    )
    context['share_url'] = share_url
    twitter_url = ''
    if context.get('twitter_share_enabled', False):
        twitter_url = 'https://twitter.com/intent/tweet?text={twitter_share_text}&url={share_url}'.format(
            twitter_share_text=smart_str(context['twitter_share_text']),
            share_url=urllib.quote_plus(smart_str(share_url))
        )
    context['twitter_url'] = twitter_url
    context['full_course_image_url'] = request.build_absolute_uri(course_image_url(course))

    # If enabled, show the LinkedIn "add to profile" button
    # Clicking this button sends the user to LinkedIn where they
    # can add the certificate information to their profile.
    linkedin_config = LinkedInAddToProfileConfiguration.current()

    # posting certificates to LinkedIn is not currently
    # supported in microsites/White Labels
    if linkedin_config.enabled and not microsite.is_request_in_microsite():
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id,
            course.display_name,
            user_certificate.mode,
            smart_str(request.build_absolute_uri(get_certificate_url(
                user_id=user.id,
                course_id=unicode(course.id)
            )))
        )
    else:
        context['linked_in_url'] = None

    # Microsites will need to be able to override any hard coded
    # content that was put into the context in the
    # _update_certificate_context() call above. For example the
    # 'company_about_description' talks about edX, which we most likely
    # do not want to keep in a microsite
    #
    # So we need to re-apply any configuration/content that
    # we are sourceing from the database. This is somewhat duplicative of
    # the code at the beginning of this method, but we
    # need the configuration at the top as some error code paths
    # require that to be set up early on in the pipeline
    #
    microsite_config_key = microsite.get_value('microsite_config_key')
    if microsite_config_key:
        context.update(configuration.get(microsite_config_key, {}))

    # track certificate evidence_visited event for analytics when certificate_user and accessing_user are different
    if request.user and request.user.id != user.id:
        emit_certificate_event('evidence_visited', user, course_id, course, {
            'certificate_id': user_certificate.verify_uuid,
            'enrollment_mode': user_certificate.mode,
            'social_network': CertificateSocialNetworks.linkedin
        })

    # Append/Override the existing view context values with any course-specific static values from Advanced Settings
    context.update(course.cert_html_view_overrides)

    # FINALLY, generate and send the output the client
    if settings.FEATURES.get('CUSTOM_CERTIFICATE_TEMPLATES_ENABLED', False):
        custom_template = get_certificate_template(course_key, user_certificate.mode)
        if custom_template:
            template = Template(
                custom_template,
                output_encoding='utf-8',
                input_encoding='utf-8',
                default_filters=['decode.utf8'],
                encoding_errors='replace',
            )
            context = RequestContext(request, context)
            return HttpResponse(template.render(context))

    return render_to_response("certificates/valid.html", context)