예제 #1
0
    def test_get_web_certificate_url(self):
        """
        Test the get_certificate_url with a web cert course
        """
        expected_url = reverse(
            'certificates:render_cert_by_uuid',
            kwargs=dict(certificate_uuid=self.uuid)
        )
        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id,
            uuid=self.uuid
        )
        self.assertEqual(expected_url, cert_url)

        expected_url = reverse(
            'certificates:html_view',
            kwargs={
                "user_id": str(self.student.id),
                "course_id": unicode(self.web_cert_course.id),
            }
        )

        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id
        )
        self.assertEqual(expected_url, cert_url)
예제 #2
0
    def test_get_web_certificate_url(self):
        """
        Test the get_certificate_url with a web cert course
        """
        expected_url = reverse(
            'certificates:render_cert_by_uuid',
            kwargs=dict(certificate_uuid=self.uuid)
        )
        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id,
            uuid=self.uuid
        )
        self.assertEqual(expected_url, cert_url)

        expected_url = reverse(
            'certificates:render_cert_by_uuid',
            kwargs=dict(certificate_uuid=self.uuid)
        )

        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id,
            uuid=self.uuid
        )
        self.assertEqual(expected_url, cert_url)
예제 #3
0
 def test_html_view_microsite_configuration_missing(self):
     test_configuration_string = """{
         "default": {
             "accomplishment_class_append": "accomplishment-certificate",
             "platform_name": "edX",
             "company_about_url": "http://www.edx.org/about-us",
             "company_privacy_url": "http://www.edx.org/edx-privacy-policy",
             "company_tos_url": "http://www.edx.org/edx-terms-service",
             "company_verified_certificate_url": "http://www.edx.org/verified-certificate",
             "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
             "logo_src": "/static/certificates/images/logo-edx.svg",
             "logo_url": "http://www.edx.org",
             "company_about_description": "This should not survive being overwritten by static content"
         },
         "honor": {
             "certificate_type": "Honor Code"
         }
     }"""
     config = self._certificate_html_view_configuration(configuration_string=test_configuration_string)
     self.assertEquals(config.configuration, test_configuration_string)
     test_url = get_certificate_url(
         user_id=self.user.id,
         course_id=unicode(self.course.id)
     )
     self._add_course_certificates(count=1, signatory_count=2)
     response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
     self.assertIn('edX', response.content)
     self.assertNotIn('platform_microsite', response.content)
     self.assertNotIn('http://www.microsite.org', response.content)
     self.assertNotIn('This should not survive being overwritten by static content', response.content)
예제 #4
0
 def test_html_view_microsite_configuration_missing(self):
     test_configuration_string = """{
         "default": {
             "accomplishment_class_append": "accomplishment-certificate",
             "platform_name": "edX",
             "company_about_url": "http://www.edx.org/about-us",
             "company_privacy_url": "http://www.edx.org/edx-privacy-policy",
             "company_tos_url": "http://www.edx.org/edx-terms-service",
             "company_verified_certificate_url": "http://www.edx.org/verified-certificate",
             "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
             "logo_src": "/static/certificates/images/logo-edx.svg",
             "logo_url": "http://www.edx.org",
             "company_about_description": "This should not survive being overwritten by static content"
         },
         "honor": {
             "certificate_type": "Honor Code"
         }
     }"""
     config = self._certificate_html_view_configuration(configuration_string=test_configuration_string)
     self.assertEquals(config.configuration, test_configuration_string)
     test_url = get_certificate_url(
         user_id=self.user.id,
         course_id=unicode(self.course.id)
     )
     self._add_course_certificates(count=1, signatory_count=2)
     response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
     self.assertIn('edX', response.content)
     self.assertNotIn('platform_microsite', response.content)
     self.assertNotIn('http://www.microsite.org', response.content)
     self.assertNotIn('This should not survive being overwritten by static content', response.content)
예제 #5
0
    def linkedin_add_to_profile_url(self):
        """
        Returns a URL to add a certificate to a LinkedIn profile (will autofill fields).

        Requires LinkedIn sharing to be enabled, either via a site configuration or a
        LinkedInAddToProfileConfiguration object being enabled.
        """
        if self.effective_user.is_anonymous:
            return

        linkedin_config = LinkedInAddToProfileConfiguration.current()
        if linkedin_config.is_enabled():
            try:
                user_certificate = GeneratedCertificate.eligible_certificates.get(
                    user=self.effective_user, course_id=self.course_key)
            except GeneratedCertificate.DoesNotExist:
                return
            cert_url = self.request.build_absolute_uri(
                get_certificate_url(course_id=self.course_key,
                                    uuid=user_certificate.verify_uuid))
            return linkedin_config.add_to_profile_url(
                self.overview.display_name,
                user_certificate.mode,
                cert_url,
                certificate=user_certificate,
            )
예제 #6
0
 def _attach_run_mode_certificate_url(self, run_mode):
     certificate_data = certificate_api.certificate_downloadable_status(self.user, self.course_key)
     certificate_uuid = certificate_data.get('uuid')
     run_mode['certificate_url'] = certificate_api.get_certificate_url(
         course_id=self.course_key,
         uuid=certificate_uuid,
     ) if certificate_uuid else None
예제 #7
0
 def _attach_run_mode_certificate_url(self, run_mode):
     certificate_data = certificate_api.certificate_downloadable_status(self.user, self.course_key)
     certificate_uuid = certificate_data.get('uuid')
     run_mode['certificate_url'] = certificate_api.get_certificate_url(
         course_id=self.course_key,
         uuid=certificate_uuid,
     ) if certificate_uuid else None
예제 #8
0
 def test_get_pdf_certificate_url(self):
     """
     Test the get_certificate_url with a pdf cert course
     """
     cert_url = get_certificate_url(user_id=self.student.id,
                                    course_id=self.pdf_cert_course.id,
                                    uuid=self.uuid)
     assert 'www.gmail.com' == cert_url
예제 #9
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for organization in program_data['organizations']:
        # TODO cache the results of the get_organization_by_short_name call
        # so we don't have to hit database that frequently
        org_obj = get_organization_by_short_name(organization['key'])
        if org_obj and org_obj.get('logo'):
            organization['img'] = org_obj['logo'].url

    for course_code in program_data['course_codes']:
        for run_mode in course_code['run_modes']:
            course_key = CourseKey.from_string(run_mode['course_key'])
            course_overview = CourseOverview.get_from_id(course_key)

            run_mode['course_url'] = reverse('course_root', args=[course_key])
            run_mode['course_image_url'] = course_overview.course_image_url

            run_mode['start_date'] = course_overview.start_datetime_text()
            run_mode['end_date'] = course_overview.end_datetime_text()

            end_date = course_overview.end or datetime.datetime.max.replace(
                tzinfo=pytz.UTC)
            run_mode['is_course_ended'] = end_date < timezone.now()

            run_mode['is_enrolled'] = CourseEnrollment.is_enrolled(
                user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(
                tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(
                tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now(
            ) < enrollment_end
            run_mode['is_enrollment_open'] = is_enrollment_open
            if not is_enrollment_open:
                # Only render this enrollment open date if the enrollment open is in the future
                run_mode['enrollment_open_date'] = strftime_localized(
                    enrollment_start, 'SHORT_DATE')

            # TODO: Currently unavailable on LMS.
            run_mode['marketing_url'] = ''

            certificate_data = certificate_api.certificate_downloadable_status(
                user, course_key)
            certificate_uuid = certificate_data.get('uuid')
            if certificate_uuid:
                run_mode[
                    'certificate_url'] = certificate_api.get_certificate_url(
                        course_id=course_key,
                        uuid=certificate_uuid,
                    )

    return program_data
예제 #10
0
 def _attach_course_run_certificate_url(self, run_mode):
     certificate_data = certificate_api.certificate_downloadable_status(self.user, self.course_run_key)
     certificate_uuid = certificate_data.get('uuid')
     run_mode['certificate_url'] = certificate_api.get_certificate_url(
         user_id=self.user.id,  # Providing user_id allows us to fall back to PDF certificates
                                # if web certificates are not configured for a given course.
         course_id=self.course_run_key,
         uuid=certificate_uuid,
     ) if certificate_uuid else None
예제 #11
0
 def test_get_pdf_certificate_url(self):
     """
     Test the get_certificate_url with a pdf cert course
     """
     cert_url = certs_api.get_certificate_url(
         user_id=self.student.id,
         course_id=self.pdf_cert_course.id,
         uuid=self.uuid)
     self.assertEqual('www.gmail.com', cert_url)
예제 #12
0
    def test_linked_student_to_web_view_credential(self, enrollment_mode):

        cert = self._create_certificate(enrollment_mode)
        test_url = get_certificate_url(course_id=self.course.id, uuid=cert.verify_uuid)

        response = self.client.get(reverse('dashboard'))

        self.assertContains(response, u'View Test_Certificate')
        self.assertContains(response, test_url)
예제 #13
0
    def test_linked_student_to_web_view_credential(self, enrollment_mode):

        cert = self._create_certificate(enrollment_mode)
        test_url = get_certificate_url(course_id=self.course.id, uuid=cert.verify_uuid)

        response = self.client.get(reverse('dashboard'))

        self.assertContains(response, u'View Test_Certificate')
        self.assertContains(response, test_url)
예제 #14
0
 def _attach_course_run_certificate_url(self, run_mode):
     certificate_data = certificate_api.certificate_downloadable_status(self.user, self.course_run_key)
     certificate_uuid = certificate_data.get('uuid')
     run_mode['certificate_url'] = certificate_api.get_certificate_url(
         user_id=self.user.id,  # Providing user_id allows us to fall back to PDF certificates
                                # if web certificates are not configured for a given course.
         course_id=self.course_run_key,
         uuid=certificate_uuid,
     ) if certificate_uuid else None
예제 #15
0
 def test_html_view_site_configuration_missing(self):
     test_url = get_certificate_url(user_id=self.user.id,
                                    course_id=six.text_type(self.course.id))
     self._add_course_certificates(count=1, signatory_count=2)
     response = self.client.get(test_url)
     self.assertIn('edX', response.content)
     self.assertNotIn('My Platform Site', response.content)
     self.assertNotIn(
         'This should not survive being overwritten by static content',
         response.content)
예제 #16
0
파일: test_views.py 프로젝트: fdns/eol-edx
 def test_html_view_for_site(self):
     test_url = get_certificate_url(
         user_id=self.user.id,
         course_id=unicode(self.course.id)
     )
     self._add_course_certificates(count=1, signatory_count=2)
     response = self.client.get(test_url)
     self.assertIn('awarded this My Platform Site Honor Code Certificate of Completion', response.content)
     self.assertIn('My Platform Site offers interactive online classes and MOOCs.', response.content)
     self.assertIn('About My Platform Site', response.content)
예제 #17
0
    def test_get_web_certificate_url(self):
        """
        Test the get_certificate_url with a web cert course
        """
        certificates = [
            {
                'id': 1,
                'name': 'Test Certificate Name',
                'description': 'Test Certificate Description',
                'course_title': 'tes_course_title',
                'signatories': [],
                'version': 1,
                'is_active': True
            }
        ]
        self.web_cert_course.certificates = {'certificates': certificates}
        self.web_cert_course.save()
        self.store.update_item(self.web_cert_course, self.student.id)

        expected_url = reverse(
            'certificates:render_cert_by_uuid',
            kwargs=dict(certificate_uuid=self.uuid)
        )
        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id,
            uuid=self.uuid
        )
        self.assertEqual(expected_url, cert_url)

        expected_url = reverse(
            'certificates:html_view',
            kwargs={
                "user_id": str(self.student.id),
                "course_id": unicode(self.web_cert_course.id),
            }
        )

        cert_url = certs_api.get_certificate_url(
            user_id=self.student.id,
            course_id=self.web_cert_course.id
        )
        self.assertEqual(expected_url, cert_url)
예제 #18
0
 def test_get_pdf_certificate_url(self):
     """
     Test the get_certificate_url with a pdf cert course
     """
     cert_url = certs_api.get_certificate_url(
         user_id=self.student.id,
         course_id=self.pdf_cert_course.id,
         uuid=self.uuid
     )
     self.assertEqual('www.gmail.com', cert_url)
예제 #19
0
 def test_html_view_for_site(self):
     test_url = get_certificate_url(user_id=self.user.id,
                                    course_id=six.text_type(self.course.id),
                                    uuid=self.cert.verify_uuid)
     self._add_course_certificates(count=1, signatory_count=2)
     response = self.client.get(test_url)
     self.assertContains(
         response,
         'awarded this My Platform Site Honor Code Certificate of Completion',
     )
     self.assertContains(
         response,
         'My Platform Site offers interactive online classes and MOOCs.')
     self.assertContains(response, 'About My Platform Site')
예제 #20
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for organization in program_data['organizations']:
        # TODO cache the results of the get_organization_by_short_name call
        # so we don't have to hit database that frequently
        org_obj = get_organization_by_short_name(organization['key'])
        if org_obj and org_obj.get('logo'):
            organization['img'] = org_obj['logo'].url

    for course_code in program_data['course_codes']:
        for run_mode in course_code['run_modes']:
            course_key = CourseKey.from_string(run_mode['course_key'])
            course_overview = CourseOverview.get_from_id(course_key)

            run_mode['course_url'] = reverse('course_root', args=[course_key])
            run_mode['course_image_url'] = course_overview.course_image_url

            run_mode['start_date'] = course_overview.start_datetime_text()
            run_mode['end_date'] = course_overview.end_datetime_text()

            end_date = course_overview.end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            run_mode['is_course_ended'] = end_date < timezone.now()

            run_mode['is_enrolled'] = CourseEnrollment.is_enrolled(user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now() < enrollment_end
            run_mode['is_enrollment_open'] = is_enrollment_open
            if not is_enrollment_open:
                # Only render this enrollment open date if the enrollment open is in the future
                run_mode['enrollment_open_date'] = strftime_localized(enrollment_start, 'SHORT_DATE')

            # TODO: Currently unavailable on LMS.
            run_mode['marketing_url'] = ''

            certificate_data = certificate_api.certificate_downloadable_status(user, course_key)
            certificate_uuid = certificate_data.get('uuid')
            if certificate_uuid:
                run_mode['certificate_url'] = certificate_api.get_certificate_url(
                    course_id=course_key,
                    uuid=certificate_uuid,
                )

    return program_data
예제 #21
0
    def test_html_view_for_microsite(self):
        test_configuration_string = """{
            "default": {
                "accomplishment_class_append": "accomplishment-certificate",
                "platform_name": "edX",
                "company_about_url": "http://www.edx.org/about-us",
                "company_privacy_url": "http://www.edx.org/edx-privacy-policy",
                "company_tos_url": "http://www.edx.org/edx-terms-service",
                "company_verified_certificate_url": "http://www.edx.org/verified-certificate",
                "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
                "logo_src": "/static/certificates/images/logo-edx.svg",
                "logo_url": "http://www.edx.org"
            },
            "microsites": {
                "test-site": {
                    "accomplishment_class_append": "accomplishment-certificate",
                    "platform_name": "platform_microsite",
                    "company_about_url": "http://www.microsite.org/about-us",
                    "company_privacy_url": "http://www.microsite.org/edx-privacy-policy",
                    "company_tos_url": "http://www.microsite.org/microsite-terms-service",
                    "company_verified_certificate_url": "http://www.microsite.org/verified-certificate",
                    "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
                    "logo_src": "/static/certificates/images/logo-microsite.svg",
                    "logo_url": "http://www.microsite.org",
                    "company_about_description": "This is special microsite aware company_about_description content",
                    "company_about_title": "Microsite title"
                }
            },
            "honor": {
                "certificate_type": "Honor Code"
            }
        }"""

        config = self._certificate_html_view_configuration(
            configuration_string=test_configuration_string)
        self.assertEquals(config.configuration, test_configuration_string)
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url,
                                   HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
        self.assertIn('platform_microsite', response.content)

        # logo url is taken from microsite configuration setting
        self.assertIn('http://test_site.localhost', response.content)
        self.assertIn(
            'This is special microsite aware company_about_description content',
            response.content)
        self.assertIn('Microsite title', response.content)
예제 #22
0
    def test_html_view_for_microsite(self):
        test_configuration_string = """{
            "default": {
                "accomplishment_class_append": "accomplishment-certificate",
                "platform_name": "edX",
                "company_about_url": "http://www.edx.org/about-us",
                "company_privacy_url": "http://www.edx.org/edx-privacy-policy",
                "company_tos_url": "http://www.edx.org/edx-terms-service",
                "company_verified_certificate_url": "http://www.edx.org/verified-certificate",
                "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
                "logo_src": "/static/certificates/images/logo-edx.svg",
                "logo_url": "http://www.edx.org"
            },
            "microsites": {
                "test-site": {
                    "accomplishment_class_append": "accomplishment-certificate",
                    "platform_name": "platform_microsite",
                    "company_about_url": "http://www.microsite.org/about-us",
                    "company_privacy_url": "http://www.microsite.org/edx-privacy-policy",
                    "company_tos_url": "http://www.microsite.org/microsite-terms-service",
                    "company_verified_certificate_url": "http://www.microsite.org/verified-certificate",
                    "document_stylesheet_url_application": "/static/certificates/sass/main-ltr.css",
                    "logo_src": "/static/certificates/images/logo-microsite.svg",
                    "logo_url": "http://www.microsite.org",
                    "company_about_description": "This is special microsite aware company_about_description content",
                    "company_about_title": "Microsite title"
                }
            },
            "honor": {
                "certificate_type": "Honor Code"
            }
        }"""

        config = self._certificate_html_view_configuration(configuration_string=test_configuration_string)
        self.assertEquals(config.configuration, test_configuration_string)
        test_url = get_certificate_url(
            user_id=self.user.id,
            course_id=unicode(self.course.id)
        )
        self._add_course_certificates(count=1, signatory_count=2)
        response = self.client.get(test_url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
        self.assertIn('platform_microsite', response.content)

        # logo url is taken from microsite configuration setting
        self.assertIn('http://test_site.localhost', response.content)
        self.assertIn('This is special microsite aware company_about_description content', response.content)
        self.assertIn('Microsite title', response.content)
예제 #23
0
    def add_certificate_footer(self):
        x, y = 11, 0.9
        sub_y = y - 0.25
        font_size = 0.15
        font_sub_size = 0.12

        if not self.is_english:
            date = trans_digits(_date(self.cert.modified_date, 'd F, Y'))
        else:
            date = self.cert.modified_date.strftime('%d %B, %Y')

        self.draw_bidi_text(self._('COURSE CERTIFICATE'), x, y, size=font_size)

        date_str = self._('Issued {date}').format(date=date)
        self.draw_bidi_text(date_str, x, sub_y, bold=True, size=font_sub_size)

        # Verification
        x = x - 3.3
        self.draw_bidi_text(
            self._('Verify the authenticity of this certificate at'),
            x,
            y,
            size=font_size)

        cert_url = get_certificate_url(course_id=self.course_id,
                                       uuid=self.cert.verify_uuid)

        url = self.path_builder(cert_url)
        cert_uuid = self.cert.verify_uuid

        qr_y = (y + sub_y) / 2.0
        self.add_qr_code(url, x, qr_y)
        self.draw_bidi_text(cert_uuid, x, sub_y, size=font_sub_size)

        # Underline the UUID
        uuid_width = stringWidth(cert_uuid, self.font, self.font_size)
        xu = self.bidi_x_axis(x * inch)
        yu = (sub_y - 0.02) * inch
        length = uuid_width if self.is_english else -uuid_width

        self.ctx.setLineWidth(0.25)
        self.ctx.line(xu, yu, xu + length, yu)

        # Link the UUID
        rect = (xu, yu, xu + length, yu + (0.5 * inch))
        self.ctx.linkURL(url, rect, relative=1)
예제 #24
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.generating)
        self.assert_event_emitted(
            'edx.certificate.created',
            user_id=self.student.id,
            course_id=unicode(self.course.id),
            certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id),
            certificate_id=cert.verify_uuid,
            enrollment_mode=cert.mode,
            generation_mode='batch'
        )
예제 #25
0
    def test_new_cert_requests_into_xqueue_returns_generating(self):
        with mock_passing_grade():
            with self._mock_queue():
                certs_api.generate_user_certificates(self.student, self.course.id)

        # Verify that the certificate has status 'generating'
        cert = GeneratedCertificate.eligible_certificates.get(user=self.student, course_id=self.course.id)
        self.assertEqual(cert.status, CertificateStatuses.generating)
        self.assert_event_emitted(
            'edx.certificate.created',
            user_id=self.student.id,
            course_id=six.text_type(self.course.id),
            certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id),
            certificate_id=cert.verify_uuid,
            enrollment_mode=cert.mode,
            generation_mode='batch'
        )
예제 #26
0
def _update_social_context(request, context, course, user, user_certificate,
                           platform_name):
    """
    Updates context dictionary with info required for social sharing.
    """
    share_settings = configuration_helpers.get_value(
        "SOCIAL_SHARING_SETTINGS", settings.SOCIAL_SHARING_SETTINGS)
    context['facebook_share_enabled'] = share_settings.get(
        'CERTIFICATE_FACEBOOK', False)
    context['facebook_app_id'] = configuration_helpers.get_value(
        "FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID)
    context['facebook_share_text'] = share_settings.get(
        'CERTIFICATE_FACEBOOK_TEXT',
        _(u"I completed the {course_title} course on {platform_name}.").format(
            course_title=context['accomplishment_copy_course_name'],
            platform_name=platform_name))
    context['twitter_share_enabled'] = share_settings.get(
        'CERTIFICATE_TWITTER', False)
    context['twitter_share_text'] = share_settings.get(
        'CERTIFICATE_TWITTER_TEXT',
        _(u"I completed a course at {platform_name}. Take a look at my certificate."
          ).format(platform_name=platform_name))

    share_url = request.build_absolute_uri(
        get_certificate_url(course_id=course.id,
                            uuid=user_certificate.verify_uuid))
    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['linked_in_url'] = None
    # 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()
    linkedin_share_enabled = share_settings.get('CERTIFICATE_LINKEDIN',
                                                linkedin_config.enabled)
    if linkedin_share_enabled:
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id, course.display_name, user_certificate.mode,
            smart_str(share_url))
예제 #27
0
def _update_social_context(request, context, course, user, user_certificate, platform_name):
    """
    Updates context dictionary with info required for social sharing.
    """
    share_settings = configuration_helpers.get_value("SOCIAL_SHARING_SETTINGS", settings.SOCIAL_SHARING_SETTINGS)
    context['facebook_share_enabled'] = share_settings.get('CERTIFICATE_FACEBOOK', False)
    context['facebook_app_id'] = configuration_helpers.get_value("FACEBOOK_APP_ID", settings.FACEBOOK_APP_ID)
    context['facebook_share_text'] = share_settings.get(
        'CERTIFICATE_FACEBOOK_TEXT',
        _(u"I completed the {course_title} course on {platform_name}.").format(
            course_title=context['accomplishment_copy_course_name'],
            platform_name=platform_name
        )
    )
    context['twitter_share_enabled'] = share_settings.get('CERTIFICATE_TWITTER', False)
    context['twitter_share_text'] = share_settings.get(
        'CERTIFICATE_TWITTER_TEXT',
        _(u"I completed a course at {platform_name}. Take a look at my certificate.").format(
            platform_name=platform_name
        )
    )

    share_url = request.build_absolute_uri(get_certificate_url(course_id=course.id, uuid=user_certificate.verify_uuid))
    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['linked_in_url'] = None
    # 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()
    linkedin_share_enabled = share_settings.get('CERTIFICATE_LINKEDIN', linkedin_config.enabled)
    if linkedin_share_enabled:
        context['linked_in_url'] = linkedin_config.add_to_profile_url(
            course.id,
            course.display_name,
            user_certificate.mode,
            smart_str(share_url)
        )
예제 #28
0
    def test_changes_on_webview(self):
        # Prepare attributes to check for
        CourseDetails.update_about_item(self.course, 'short_description',
                                        'Edraak Test Description',
                                        self.user.id)

        # Creating a certificate
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_edraak_test_template()
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))

        # Getting certificate as HTML
        response = self.client.get(test_url)

        # Verifying contents
        self.assertContains(response, 'Edraak Template')
        self.assertContains(response,
                            'course_description: Edraak Test Description')
예제 #29
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for course_code in program_data['course_codes']:
        for run_mode in course_code['run_modes']:
            course_key = CourseKey.from_string(run_mode['course_key'])
            course_overview = CourseOverview.get_from_id(course_key)

            run_mode['course_url'] = reverse('course_root', args=[course_key])
            run_mode['course_image_url'] = course_overview.course_image_url

            human_friendly_format = '%x'
            start_date = course_overview.start or DEFAULT_START_DATE
            end_date = course_overview.end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            run_mode['start_date'] = start_date.strftime(human_friendly_format)
            run_mode['end_date'] = end_date.strftime(human_friendly_format)

            run_mode['is_enrolled'] = CourseEnrollment.is_enrolled(user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now() < enrollment_end
            run_mode['is_enrollment_open'] = is_enrollment_open

            # TODO: Currently unavailable on LMS.
            run_mode['marketing_url'] = ''

            certificate_data = certificate_api.certificate_downloadable_status(user, course_key)
            certificate_uuid = certificate_data.get('uuid')
            if certificate_uuid:
                run_mode['certificate_url'] = certificate_api.get_certificate_url(
                    course_id=course_key,
                    uuid=certificate_uuid,
                )

    return program_data
예제 #30
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for course_code in program_data["course_codes"]:
        for run_mode in course_code["run_modes"]:
            course_key = CourseKey.from_string(run_mode["course_key"])
            course_overview = CourseOverview.get_from_id(course_key)

            run_mode["course_url"] = reverse("course_root", args=[course_key])
            run_mode["course_image_url"] = course_overview.course_image_url

            human_friendly_format = "%x"
            start_date = course_overview.start or DEFAULT_START_DATE
            end_date = course_overview.end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            run_mode["start_date"] = start_date.strftime(human_friendly_format)
            run_mode["end_date"] = end_date.strftime(human_friendly_format)

            run_mode["is_enrolled"] = CourseEnrollment.is_enrolled(user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now() < enrollment_end
            run_mode["is_enrollment_open"] = is_enrollment_open

            # TODO: Currently unavailable on LMS.
            run_mode["marketing_url"] = ""

            certificate_data = certificate_api.certificate_downloadable_status(user, course_key)
            certificate_uuid = certificate_data.get("uuid")
            if certificate_uuid:
                run_mode["certificate_url"] = certificate_api.get_certificate_url(
                    course_id=course_key, uuid=certificate_uuid
                )

    return program_data
예제 #31
0
    def test_course_metadata(self, logged_in, enrollment_mode,
                             enable_anonymous,
                             is_microfrontend_enabled_for_user):
        is_microfrontend_enabled_for_user.return_value = True
        check_public_access = mock.Mock()
        check_public_access.return_value = enable_anonymous
        with mock.patch(
                'lms.djangoapps.courseware.access_utils.check_public_access',
                check_public_access):
            if not logged_in:
                self.client.logout()
            if enrollment_mode == 'verified':
                cert = GeneratedCertificateFactory.create(
                    user=self.user,
                    course_id=self.course.id,
                    status='downloadable',
                    mode='verified',
                )
            if enrollment_mode:
                CourseEnrollment.enroll(self.user, self.course.id,
                                        enrollment_mode)

            response = self.client.get(self.url)
            assert response.status_code == 200
            if enrollment_mode:
                enrollment = response.data['enrollment']
                assert enrollment_mode == enrollment['mode']
                assert enrollment['is_active']
                assert len(response.data['tabs']) == 6
                found = False
                for tab in response.data['tabs']:
                    if tab['type'] == 'external_link':
                        assert tab[
                            'url'] != 'http://hidden.com', "Hidden tab is not hidden"
                        if tab['url'] == 'http://zombo.com':
                            found = True
                assert found, 'external link not in course tabs'

                assert not response.data['user_has_passing_grade']
                if enrollment_mode == 'audit':
                    assert response.data['verify_identity_url'] is None
                    assert response.data['verification_status'] == 'none'  # lint-amnesty, pylint: disable=literal-comparison
                    assert response.data['linkedin_add_to_profile_url'] is None
                else:
                    assert response.data['certificate_data'][
                        'cert_status'] == 'earned_but_not_available'
                    expected_verify_identity_url = IDVerificationService.get_verify_location(
                        course_id=self.course.id)
                    # The response contains an absolute URL so this is only checking the path of the final
                    assert expected_verify_identity_url in response.data[
                        'verify_identity_url']
                    assert response.data['verification_status'] == 'none'  # lint-amnesty, pylint: disable=literal-comparison

                    request = RequestFactory().request()
                    cert_url = get_certificate_url(course_id=self.course.id,
                                                   uuid=cert.verify_uuid)
                    linkedin_url_params = {
                        'name':
                        '{platform_name} Verified Certificate for {course_name}'
                        .format(
                            platform_name=settings.PLATFORM_NAME,
                            course_name=self.course.display_name,
                        ),
                        'certUrl':
                        request.build_absolute_uri(cert_url),
                        # default value from the LinkedInAddToProfileConfigurationFactory company_identifier
                        'organizationId':
                        1337,
                        'certId':
                        cert.verify_uuid,
                        'issueYear':
                        cert.created_date.year,
                        'issueMonth':
                        cert.created_date.month,
                    }
                    expected_linkedin_url = (
                        'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&{params}'
                        .format(params=urlencode(linkedin_url_params)))
                    assert response.data[
                        'linkedin_add_to_profile_url'] == expected_linkedin_url
            elif enable_anonymous and not logged_in:
                # multiple checks use this handler
                check_public_access.assert_called()
                assert response.data['enrollment']['mode'] is None
                assert response.data['course_access']['has_access']
            else:
                assert not response.data['course_access']['has_access']
예제 #32
0
def _cert_info(user, enrollment, cert_status):
    """
    Implements the logic for cert_info -- split out for testing.

    TODO: replace with a method that lives in the certificates app and combines this logic with
     lms.djangoapps.certificates.api.can_show_certificate_message and
     lms.djangoapps.courseware.views.get_cert_data

    Arguments:
        user (User): A user.
        enrollment (CourseEnrollment): A course enrollment.
        cert_status (dict): dictionary containing information about certificate status for the user

    Returns:
        dictionary containing:
            'status': one of 'generating', 'downloadable', 'notpassing', 'restricted', 'auditing',
                'processing', 'unverified', 'unavailable', or 'certificate_earned_but_not_available'
            'show_survey_button': bool
            'can_unenroll': if status allows for unenrollment

        The dictionary may also contain:
            'linked_in_url': url to add cert to LinkedIn profile
            'survey_url': url, only if course_overview.end_of_course_survey_url is not None
            'show_cert_web_view': bool if html web certs are enabled and there is an active web cert
            'cert_web_view_url': url if html web certs are enabled and there is an active web cert
            'download_url': url to download a cert
            'grade': if status is in 'generating', 'downloadable', 'notpassing', 'restricted',
                'auditing', or 'unverified'
    """
    # simplify the status for the template using this lookup table
    template_state = {
        CertificateStatuses.generating: 'generating',
        CertificateStatuses.downloadable: 'downloadable',
        CertificateStatuses.notpassing: 'notpassing',
        CertificateStatuses.restricted: 'restricted',
        CertificateStatuses.auditing: 'auditing',
        CertificateStatuses.audit_passing: 'auditing',
        CertificateStatuses.audit_notpassing: 'auditing',
        CertificateStatuses.unverified: 'unverified',
    }

    certificate_earned_but_not_available_status = 'certificate_earned_but_not_available'
    default_status = 'processing'

    default_info = {
        'status': default_status,
        'show_survey_button': False,
        'can_unenroll': True,
    }

    if cert_status is None or enrollment is None:
        return default_info

    course_overview = enrollment.course_overview if enrollment else None
    status = template_state.get(cert_status['status'], default_status)
    is_hidden_status = status in ('processing', 'generating', 'notpassing',
                                  'auditing')

    if _is_certificate_earned_but_not_available(course_overview, status):
        status = certificate_earned_but_not_available_status

    if (course_overview.certificates_display_behavior
            == CertificatesDisplayBehaviors.EARLY_NO_INFO
            and is_hidden_status):
        return default_info

    if not CourseMode.is_eligible_for_certificate(enrollment.mode,
                                                  status=status):
        return default_info

    if course_overview and access.is_beta_tester(user, course_overview.id):
        # Beta testers are not eligible for a course certificate
        return default_info

    status_dict = {
        'status': status,
        'mode': cert_status.get('mode', None),
        'linked_in_url': None,
        'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES,
    }

    if status != default_status and course_overview.end_of_course_survey_url is not None:
        status_dict.update({
            'show_survey_button':
            True,
            'survey_url':
            process_survey_link(course_overview.end_of_course_survey_url, user)
        })
    else:
        status_dict['show_survey_button'] = False

    if status == 'downloadable':
        # showing the certificate web view button if certificate is downloadable state and feature flags are enabled.
        if has_html_certificates_enabled(course_overview):
            if course_overview.has_any_active_web_certificate:
                status_dict.update({
                    'show_cert_web_view':
                    True,
                    'cert_web_view_url':
                    get_certificate_url(course_id=course_overview.id,
                                        uuid=cert_status['uuid'])
                })
            elif cert_status['download_url']:
                status_dict['download_url'] = cert_status['download_url']
            else:
                # don't show download certificate button if we don't have an active certificate for course
                status_dict['status'] = 'unavailable'
        elif 'download_url' not in cert_status:
            log.warning(
                "User %s has a downloadable cert for %s, but no download url",
                user.username, course_overview.id)
            return default_info
        else:
            status_dict['download_url'] = cert_status['download_url']

            # 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.is_enabled():
                status_dict[
                    'linked_in_url'] = linkedin_config.add_to_profile_url(
                        course_overview.display_name,
                        cert_status.get('mode'),
                        cert_status['download_url'],
                    )

    if status in {
            'generating', 'downloadable', 'notpassing', 'restricted',
            'auditing', 'unverified'
    }:
        cert_grade_percent = -1
        persisted_grade_percent = -1
        persisted_grade = CourseGradeFactory().read(user,
                                                    course=course_overview,
                                                    create_if_needed=False)
        if persisted_grade is not None:
            persisted_grade_percent = persisted_grade.percent

        if 'grade' in cert_status:
            cert_grade_percent = float(cert_status['grade'])

        if cert_grade_percent == -1 and persisted_grade_percent == -1:
            # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x,
            # who need to be regraded (we weren't tracking 'notpassing' at first).
            # We can add a log.warning here once we think it shouldn't happen.
            return default_info
        grades_input = [cert_grade_percent, persisted_grade_percent]
        max_grade = (None if all(grade is None for grade in grades_input) else
                     max(filter(lambda x: x is not None, grades_input)))
        status_dict['grade'] = str(max_grade)

        # If the grade is passing, the status is one of these statuses, and request certificate
        # is enabled for a course then we need to provide the option to the learner
        cert_gen_enabled = (has_self_generated_certificates_enabled(
            course_overview.id) or auto_certificate_generation_enabled())
        passing_grade = persisted_grade and persisted_grade.passed
        if (status_dict['status'] != CertificateStatuses.downloadable
                and cert_gen_enabled and passing_grade
                and course_overview.has_any_active_web_certificate):
            status_dict['status'] = CertificateStatuses.requesting

    return status_dict
예제 #33
0
    def test_enrolled_course_metadata(self, logged_in, enrollment_mode):
        check_public_access = mock.Mock()
        check_public_access.return_value = ACCESS_DENIED
        with mock.patch('lms.djangoapps.courseware.access_utils.check_public_access', check_public_access):
            if not logged_in:
                self.client.logout()
            if enrollment_mode == 'verified':
                cert = GeneratedCertificateFactory.create(
                    user=self.user,
                    course_id=self.course.id,
                    status='downloadable',
                    mode='verified',
                )
            if enrollment_mode:
                CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)

            response = self.client.get(self.url)
            assert response.status_code == 200

            enrollment = response.data['enrollment']
            assert enrollment_mode == enrollment['mode']
            assert enrollment['is_active']

            assert not response.data['user_has_passing_grade']
            assert response.data['celebrations']['first_section']
            assert not response.data['celebrations']['weekly_goal']

            # This import errors in cms if it is imported at the top level
            from lms.djangoapps.course_goals.api import get_course_goal
            selected_goal = get_course_goal(self.user, self.course.id)
            if selected_goal:
                assert response.data['course_goals']['selected_goal'] == {
                    'days_per_week': selected_goal.days_per_week,
                    'subscribed_to_reminders': selected_goal.subscribed_to_reminders,
                }

            if enrollment_mode == 'audit':
                assert response.data['verify_identity_url'] is None
                assert response.data['verification_status'] == 'none'
                assert response.data['linkedin_add_to_profile_url'] is None
            else:
                assert response.data['certificate_data']['cert_status'] == 'earned_but_not_available'
                expected_verify_identity_url = IDVerificationService.get_verify_location(
                    course_id=self.course.id
                )
                # The response contains an absolute URL so this is only checking the path of the final
                assert expected_verify_identity_url in response.data['verify_identity_url']
                assert response.data['verification_status'] == 'none'

                request = RequestFactory().request()
                cert_url = get_certificate_url(course_id=self.course.id, uuid=cert.verify_uuid)
                linkedin_url_params = {
                    'name': '{platform_name} Verified Certificate for {course_name}'.format(
                        platform_name=settings.PLATFORM_NAME, course_name=self.course.display_name,
                    ),
                    'certUrl': request.build_absolute_uri(cert_url),
                    # default value from the LinkedInAddToProfileConfigurationFactory company_identifier
                    'organizationId': 1337,
                    'certId': cert.verify_uuid,
                    'issueYear': cert.created_date.year,
                    'issueMonth': cert.created_date.month,
                }
                expected_linkedin_url = (
                    'https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&{params}'.format(
                        params=urlencode(linkedin_url_params)
                    )
                )
                assert response.data['linkedin_add_to_profile_url'] == expected_linkedin_url
예제 #34
0
 def test_cert_url_empty_with_invalid_certificate(self):
     """
     Test certificate url is empty if html view is not enabled and certificate is not yet generated
     """
     url = certs_api.get_certificate_url(self.student.id, self.course.id)
     self.assertEqual(url, "")
예제 #35
0
 def test_cert_url_empty_with_invalid_certificate(self):
     """
     Test certificate url is empty if html view is not enabled and certificate is not yet generated
     """
     url = certs_api.get_certificate_url(self.student.id, self.course.id)
     self.assertEqual(url, "")
예제 #36
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for organization in program_data['organizations']:
        # TODO: Cache the results of the get_organization_by_short_name call so
        # the database is hit less frequently.
        org_obj = get_organization_by_short_name(organization['key'])
        if org_obj and org_obj.get('logo'):
            organization['img'] = org_obj['logo'].url

    for course_code in program_data['course_codes']:
        for run_mode in course_code['run_modes']:
            course_key = CourseKey.from_string(run_mode['course_key'])
            course_overview = CourseOverview.get_from_id(course_key)

            course_url = reverse('course_root', args=[course_key])
            course_image_url = course_overview.course_image_url

            start_date_string = course_overview.start_datetime_text()
            end_date_string = course_overview.end_datetime_text()

            end_date = course_overview.end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            is_course_ended = end_date < timezone.now()

            is_enrolled = CourseEnrollment.is_enrolled(user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now() < enrollment_end

            enrollment_open_date = None if is_enrollment_open else strftime_localized(enrollment_start, 'SHORT_DATE')

            certificate_data = certificate_api.certificate_downloadable_status(user, course_key)
            certificate_uuid = certificate_data.get('uuid')
            certificate_url = certificate_api.get_certificate_url(
                course_id=course_key,
                uuid=certificate_uuid,
            ) if certificate_uuid else None

            required_mode_slug = run_mode['mode_slug']
            enrolled_mode_slug, _ = CourseEnrollment.enrollment_mode_for_user(user, course_key)
            is_mode_mismatch = required_mode_slug != enrolled_mode_slug
            is_upgrade_required = is_enrolled and is_mode_mismatch

            # Requires that the ecommerce service be in use.
            required_mode = CourseMode.mode_for_course(course_key, required_mode_slug)
            ecommerce = EcommerceService()
            sku = getattr(required_mode, 'sku', None)

            if ecommerce.is_enabled(user) and sku:
                upgrade_url = ecommerce.checkout_page_url(required_mode.sku) if is_upgrade_required else None
            else:
                upgrade_url = None

            run_mode.update({
                'certificate_url': certificate_url,
                'course_image_url': course_image_url,
                'course_url': course_url,
                'end_date': end_date_string,
                'enrollment_open_date': enrollment_open_date,
                'is_course_ended': is_course_ended,
                'is_enrolled': is_enrolled,
                'is_enrollment_open': is_enrollment_open,
                'marketing_url': get_run_marketing_url(course_key, user),
                'start_date': start_date_string,
                'upgrade_url': upgrade_url,
            })

    return program_data
예제 #37
0
def supplement_program_data(program_data, user):
    """Supplement program course codes with CourseOverview and CourseEnrollment data.

    Arguments:
        program_data (dict): Representation of a program.
        user (User): The user whose enrollments to inspect.
    """
    for organization in program_data['organizations']:
        # TODO: Cache the results of the get_organization_by_short_name call so
        # the database is hit less frequently.
        org_obj = get_organization_by_short_name(organization['key'])
        if org_obj and org_obj.get('logo'):
            organization['img'] = org_obj['logo'].url

    for course_code in program_data['course_codes']:
        for run_mode in course_code['run_modes']:
            course_key = CourseKey.from_string(run_mode['course_key'])
            course_overview = CourseOverview.get_from_id(course_key)

            course_url = reverse('course_root', args=[course_key])
            course_image_url = course_overview.course_image_url

            start_date_string = course_overview.start_datetime_text()
            end_date_string = course_overview.end_datetime_text()

            end_date = course_overview.end or datetime.datetime.max.replace(
                tzinfo=pytz.UTC)
            is_course_ended = end_date < timezone.now()

            is_enrolled = CourseEnrollment.is_enrolled(user, course_key)

            enrollment_start = course_overview.enrollment_start or datetime.datetime.min.replace(
                tzinfo=pytz.UTC)
            enrollment_end = course_overview.enrollment_end or datetime.datetime.max.replace(
                tzinfo=pytz.UTC)
            is_enrollment_open = enrollment_start <= timezone.now(
            ) < enrollment_end

            enrollment_open_date = None if is_enrollment_open else strftime_localized(
                enrollment_start, 'SHORT_DATE')

            certificate_data = certificate_api.certificate_downloadable_status(
                user, course_key)
            certificate_uuid = certificate_data.get('uuid')
            certificate_url = certificate_api.get_certificate_url(
                course_id=course_key,
                uuid=certificate_uuid,
            ) if certificate_uuid else None

            required_mode_slug = run_mode['mode_slug']
            enrolled_mode_slug, _ = CourseEnrollment.enrollment_mode_for_user(
                user, course_key)
            is_mode_mismatch = required_mode_slug != enrolled_mode_slug
            is_upgrade_required = is_enrolled and is_mode_mismatch

            # Requires that the ecommerce service be in use.
            required_mode = CourseMode.mode_for_course(course_key,
                                                       required_mode_slug)
            ecommerce = EcommerceService()
            sku = getattr(required_mode, 'sku', None)

            if ecommerce.is_enabled(user) and sku:
                upgrade_url = ecommerce.checkout_page_url(
                    required_mode.sku) if is_upgrade_required else None
            else:
                upgrade_url = None

            run_mode.update({
                'certificate_url': certificate_url,
                'course_image_url': course_image_url,
                'course_url': course_url,
                'end_date': end_date_string,
                'enrollment_open_date': enrollment_open_date,
                'is_course_ended': is_course_ended,
                'is_enrolled': is_enrolled,
                'is_enrollment_open': is_enrollment_open,
                # TODO: Not currently available on LMS.
                'marketing_url': None,
                'start_date': start_date_string,
                'upgrade_url': upgrade_url,
            })

    return program_data
예제 #38
0
 def test_cert_url_empty_with_invalid_certificate(self):
     """
     Test certificate url is empty if html view is not enabled and certificate is not yet generated
     """
     url = get_certificate_url(self.user.id, self.course_run_key)
     assert url == ''
예제 #39
0
def _update_certificate_context(context,
                                course,
                                user_certificate,
                                platform_name,
                                preview_mode=None):
    """
    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
    certificate_type = context.get('certificate_type')

    # 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'))

    context['certificate_absolute_url'] = get_certificate_url(
        course_id=course.id, uuid=user_certificate.verify_uuid)

    # Translators:  The format of the date includes the full name of the month
    if preview_mode:
        date = datetime.now()
    else:
        date = display_date_for_certificate(course, user_certificate)
    context['certificate_date_issued'] = _('{month} {day}, {year}').format(
        month=strftime_localized(date, "%B"), day=date.day, year=date.year)

    # 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=context['accomplishment_copy_name'],
            partner_short_name=context['organization_short_name'],
            course_number=context['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=context['organization_short_name'],
             course_number=context['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 this {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 text describes the purpose (and therefore, value) of a course certificate
    context['certificate_info_description'] = _(
        "{platform_name} acknowledges achievements through "
        "certificates, which are awarded for course activities "
        "that {platform_name} students complete.").format(
            platform_name=platform_name,
            tos_url=context.get('company_tos_url'),
            verified_cert_url=context.get('company_verified_certificate_url'))
예제 #40
0
def _cert_info(user, course_overview, cert_status):
    """
    Implements the logic for cert_info -- split out for testing.

    Arguments:
        user (User): A user.
        course_overview (CourseOverview): A course.
    """
    # simplify the status for the template using this lookup table
    template_state = {
        CertificateStatuses.generating: 'generating',
        CertificateStatuses.downloadable: 'downloadable',
        CertificateStatuses.notpassing: 'notpassing',
        CertificateStatuses.restricted: 'restricted',
        CertificateStatuses.auditing: 'auditing',
        CertificateStatuses.audit_passing: 'auditing',
        CertificateStatuses.audit_notpassing: 'auditing',
        CertificateStatuses.unverified: 'unverified',
    }

    certificate_earned_but_not_available_status = 'certificate_earned_but_not_available'
    default_status = 'processing'

    default_info = {
        'status': default_status,
        'show_survey_button': False,
        'can_unenroll': True,
    }

    if cert_status is None:
        return default_info

    status = template_state.get(cert_status['status'], default_status)
    is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing')

    if (
        not certificates_viewable_for_course(course_overview) and
        (status in CertificateStatuses.PASSED_STATUSES) and
        course_overview.certificate_available_date
    ):
        status = certificate_earned_but_not_available_status

    if (
        course_overview.certificates_display_behavior == 'early_no_info' and
        is_hidden_status
    ):
        return default_info

    status_dict = {
        'status': status,
        'mode': cert_status.get('mode', None),
        'linked_in_url': None,
        'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES,
    }

    if status != default_status and course_overview.end_of_course_survey_url is not None:
        status_dict.update({
            'show_survey_button': True,
            'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)})
    else:
        status_dict['show_survey_button'] = False

    if status == 'downloadable':
        # showing the certificate web view button if certificate is downloadable state and feature flags are enabled.
        if has_html_certificates_enabled(course_overview):
            if course_overview.has_any_active_web_certificate:
                status_dict.update({
                    'show_cert_web_view': True,
                    'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid'])
                })
            else:
                # don't show download certificate button if we don't have an active certificate for course
                status_dict['status'] = 'unavailable'
        elif 'download_url' not in cert_status:
            log.warning(
                u"User %s has a downloadable cert for %s, but no download url",
                user.username,
                course_overview.id
            )
            return default_info
        else:
            status_dict['download_url'] = cert_status['download_url']

            # 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 White Labels
            if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site():
                status_dict['linked_in_url'] = linkedin_config.add_to_profile_url(
                    course_overview.id,
                    course_overview.display_name,
                    cert_status.get('mode'),
                    cert_status['download_url']
                )

    if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}:
        cert_grade_percent = -1
        persisted_grade_percent = -1
        persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False)
        if persisted_grade is not None:
            persisted_grade_percent = persisted_grade.percent

        if 'grade' in cert_status:
            cert_grade_percent = float(cert_status['grade'])

        if cert_grade_percent == -1 and persisted_grade_percent == -1:
            # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x,
            # who need to be regraded (we weren't tracking 'notpassing' at first).
            # We can add a log.warning here once we think it shouldn't happen.
            return default_info

        status_dict['grade'] = text_type(max(cert_grade_percent, persisted_grade_percent))

    return status_dict
예제 #41
0
def _cert_info(user, course_overview, cert_status):
    """
    Implements the logic for cert_info -- split out for testing.

    Arguments:
        user (User): A user.
        course_overview (CourseOverview): A course.
    """
    # simplify the status for the template using this lookup table
    template_state = {
        CertificateStatuses.generating: 'generating',
        CertificateStatuses.downloadable: 'downloadable',
        CertificateStatuses.notpassing: 'notpassing',
        CertificateStatuses.restricted: 'restricted',
        CertificateStatuses.auditing: 'auditing',
        CertificateStatuses.audit_passing: 'auditing',
        CertificateStatuses.audit_notpassing: 'auditing',
        CertificateStatuses.unverified: 'unverified',
    }

    certificate_earned_but_not_available_status = 'certificate_earned_but_not_available'
    default_status = 'processing'

    default_info = {
        'status': default_status,
        'show_survey_button': False,
        'can_unenroll': True,
    }

    if cert_status is None:
        return default_info

    status = template_state.get(cert_status['status'], default_status)
    is_hidden_status = status in ('unavailable', 'processing', 'generating', 'notpassing', 'auditing')

    if (
        not certificates_viewable_for_course(course_overview) and
        (status in CertificateStatuses.PASSED_STATUSES) and
        course_overview.certificate_available_date
    ):
        status = certificate_earned_but_not_available_status

    if (
        course_overview.certificates_display_behavior == 'early_no_info' and
        is_hidden_status
    ):
        return default_info

    status_dict = {
        'status': status,
        'mode': cert_status.get('mode', None),
        'linked_in_url': None,
        'can_unenroll': status not in DISABLE_UNENROLL_CERT_STATES,
    }

    if status != default_status and course_overview.end_of_course_survey_url is not None:
        status_dict.update({
            'show_survey_button': True,
            'survey_url': process_survey_link(course_overview.end_of_course_survey_url, user)})
    else:
        status_dict['show_survey_button'] = False

    if status == 'downloadable':
        # showing the certificate web view button if certificate is downloadable state and feature flags are enabled.
        if has_html_certificates_enabled(course_overview):
            if course_overview.has_any_active_web_certificate:
                status_dict.update({
                    'show_cert_web_view': True,
                    'cert_web_view_url': get_certificate_url(course_id=course_overview.id, uuid=cert_status['uuid'])
                })
            else:
                # don't show download certificate button if we don't have an active certificate for course
                status_dict['status'] = 'unavailable'
        elif 'download_url' not in cert_status:
            log.warning(
                u"User %s has a downloadable cert for %s, but no download url",
                user.username,
                course_overview.id
            )
            return default_info
        else:
            status_dict['download_url'] = cert_status['download_url']

            # 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 White Labels
            if linkedin_config.enabled and not theming_helpers.is_request_in_themed_site():
                status_dict['linked_in_url'] = linkedin_config.add_to_profile_url(
                    course_overview.id,
                    course_overview.display_name,
                    cert_status.get('mode'),
                    cert_status['download_url']
                )

    if status in {'generating', 'downloadable', 'notpassing', 'restricted', 'auditing', 'unverified'}:
        cert_grade_percent = -1
        persisted_grade_percent = -1
        persisted_grade = CourseGradeFactory().read(user, course=course_overview, create_if_needed=False)
        if persisted_grade is not None:
            persisted_grade_percent = persisted_grade.percent

        if 'grade' in cert_status:
            cert_grade_percent = float(cert_status['grade'])

        if cert_grade_percent == -1 and persisted_grade_percent == -1:
            # Note: as of 11/20/2012, we know there are students in this state-- cs169.1x,
            # who need to be regraded (we weren't tracking 'notpassing' at first).
            # We can add a log.warning here once we think it shouldn't happen.
            return default_info
        grades_input = [cert_grade_percent, persisted_grade_percent]
        max_grade = None if all(grade is None for grade in grades_input) else max(filter(lambda x: x is not None, grades_input))
        status_dict['grade'] = text_type(max_grade)

    return status_dict
예제 #42
0
def generate_user_cert(request, course_id):
    """Start generating a new certificate for the user.

    Certificate generation is allowed if:
    * The user has passed the course, and
    * The user does not already have a pending/completed certificate.

    Note that if an error occurs during certificate generation
    (for example, if the queue is down), then we simply mark the
    certificate generation task status as "error" and re-run
    the task with a management command.  To students, the certificate
    will appear to be "generating" until it is re-run.

    Args:
        request (HttpRequest): The POST request to this view.
        course_id (unicode): The identifier for the course.

    Returns:
        HttpResponse: 200 on success, 400 if a new certificate cannot be generated.

    """

    if not request.user.is_authenticated():
        log.info(u"Anon user trying to generate certificate for %s", course_id)
        return HttpResponseBadRequest(
            _('You must be signed in to {platform_name} to create a certificate.'
              ).format(platform_name=configuration_helpers.get_value(
                  'PLATFORM_NAME', settings.PLATFORM_NAME)))

    student = request.user
    course_key = CourseKey.from_string(course_id)

    course = modulestore().get_course(course_key, depth=2)
    if not course:
        return HttpResponseBadRequest(_("Course is not valid"))

    if not is_course_passed(course, None, student, request):
        return HttpResponseBadRequest(
            _("Your certificate will be available when you pass the course."))

    certificate_status = certs_api.certificate_downloadable_status(
        student, course.id)

    if certificate_status["is_downloadable"]:
        return HttpResponseBadRequest(
            _("Certificate has already been created."))
    elif certificate_status["is_generating"]:
        return HttpResponseBadRequest(_("Certificate is being created."))
    else:
        # If the certificate is not already in-process or completed,
        # then create a new certificate generation task.
        # If the certificate cannot be added to the queue, this will
        # mark the certificate with "error" status, so it can be re-run
        # with a management command.  From the user's perspective,
        # it will appear that the certificate task was submitted successfully.
        base_url = settings.LMS_ROOT_URL
        MandrillClient().send_mail(
            MandrillClient.COURSE_COMPLETION_TEMPLATE, student.email, {
                'course_name':
                course.display_name,
                'course_url':
                get_course_link(course_id=course.id),
                'full_name':
                student.first_name + " " + student.last_name,
                'certificate_url':
                base_url +
                get_certificate_url(user_id=student.id, course_id=course.id),
                'course_library_url':
                base_url + '/courses',
            })
        certs_api.generate_user_certificates(student,
                                             course.id,
                                             course=course,
                                             generation_mode='self')
        _track_successful_certificate_generation(student.id, course.id)
        return HttpResponse()