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 = ""
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
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)
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
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
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))
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')
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
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)
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')
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))
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')
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})
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')
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 ) )
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' )
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 ) )
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)
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' )
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='_'), }
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 }
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 }
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
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
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, }
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
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
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
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)
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
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 })
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
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
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
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
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='_'), }
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
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)
def get_image_url(self, course): """ Get the course image URL """ return course_image_url(course)
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 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')
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')
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')
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})
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
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'] = '© {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 & characters represent an ampersand character and can be ignored context['company_tos_urltext'] = _("Terms of Service & 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)
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')
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""".').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)
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')
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""".').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 )
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()
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'] = '© {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 & characters represent an ampersand character and can be ignored context['company_tos_urltext'] = _("Terms of Service & 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)