예제 #1
0
    def test_certificate_footer_data(self):
        """
        Test that get_certificate_footer_context from certificates api returns
        data customized according to site branding.
        """
        # Generate certificates for the course
        CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug=CourseMode.HONOR)
        data = certs_api.get_certificate_footer_context()

        # Make sure there are not unexpected keys in dict returned by 'get_certificate_footer_context'
        self.assertItemsEqual(
            data.keys(),
            ['company_about_url', 'company_privacy_url', 'company_tos_url']
        )

        # ABOUT is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url
        self.assertIn(
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['ABOUT'],
            data['company_about_url']
        )

        # PRIVACY is present in MICROSITE_CONFIGURATION['test_microsite']["urls"] so web certificate will use that url
        self.assertIn(
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['PRIVACY'],
            data['company_privacy_url']
        )

        # TOS_AND_HONOR is present in MICROSITE_CONFIGURATION['test_microsite']["urls"],
        # so web certificate will use that url
        self.assertIn(
            settings.MICROSITE_CONFIGURATION['test_microsite']["urls"]['TOS_AND_HONOR'],
            data['company_tos_url']
        )
예제 #2
0
    def test_access_denied_fragment_for_masquerading(self):
        """
        Test that a global staff sees gated content flag when viewing course as `Learner in Limited Access`
        Note: Global staff doesn't require to be enrolled in course.
        """
        mock_request = RequestFactory().get('/')
        mock_course = Mock(id=self.course_key, user_partitions={})
        mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id)))
        mock_course_masquerade = Mock(
            role='student',
            user_partition_id=CONTENT_GATING_PARTITION_ID,
            group_id=LIMITED_ACCESS.id,
            user_name=None
        )
        CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified')

        global_staff = GlobalStaffFactory.create()
        ContentTypeGatingConfig.objects.create(enabled=False, studio_override_enabled=True)

        partition = create_content_gating_partition(mock_course)

        with patch(
            'crum.get_current_request',
            return_value=mock_request
        ):
            fragment = partition.access_denied_fragment(mock_block, global_staff, LIMITED_ACCESS, [FULL_ACCESS])

        self.assertIsNotNone(fragment)
예제 #3
0
    def test_professional_enrollment(self, mode):
        # The only course mode is professional ed
        CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=1)

        # Go to the "choose your track" page
        choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(choose_track_url)

        # Since the only available track is professional ed, expect that
        # we're redirected immediately to the start of the payment flow.
        purchase_workflow = "?purchase_workflow=single"
        start_flow_url = reverse('verify_student_start_flow', args=[unicode(self.course.id)]) + purchase_workflow
        self.assertRedirects(response, start_flow_url)

        # Now enroll in the course
        CourseEnrollmentFactory(
            user=self.user,
            is_active=True,
            mode=mode,
            course_id=unicode(self.course.id),
        )

        # Expect that this time we're redirected to the dashboard (since we're already registered)
        response = self.client.get(choose_track_url)
        self.assertRedirects(response, reverse('dashboard'))
예제 #4
0
    def test_enterprise_learner_context(self):
        """
        Test: Track selection page should show the enterprise context message if user belongs to the Enterprise.
        """
        # Create the course modes
        for mode in ('audit', 'honor', 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        self.mock_enterprise_learner_api()

        self.mock_course_discovery_api_for_catalog_contains(
            catalog_id=1, course_run_ids=[str(self.course.id)]
        )

        # User visits the track selection page directly without ever enrolling
        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)
        self.assertContains(
            response,
            'Welcome, {username}! You are about to enroll in {course_name}, from {partner_names}, '
            'sponsored by TestShib. Please select your enrollment information below.'.format(
                username=self.user.username,
                course_name=self.course.display_name_with_default_escaped,
                partner_names=self.course.org
            )
        )
예제 #5
0
    def test_access_denied_fragment_for_masquerading(self):
        """
        Test that a global staff sees gated content flag when viewing course as `Learner in Audit`
        Note: Global staff doesn't require to be enrolled in course.
        """
        mock_request = RequestFactory().get('/')
        mock_course = Mock(id=self.course_key, user_partitions={})
        mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id)))
        mock_course_masquerade = Mock(
            role='student',
            user_partition_id=ENROLLMENT_TRACK_PARTITION_ID,
            group_id=settings.COURSE_ENROLLMENT_MODES['audit']['id'],
            user_name=None
        )
        CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified')

        global_staff = GlobalStaffFactory.create()
        ContentTypeGatingConfig.objects.create(enabled=False, studio_override_enabled=True)

        partition = create_content_gating_partition(mock_course)

        with patch(
            'courseware.masquerade.get_course_masquerade',
            return_value=mock_course_masquerade
        ), patch(
            'openedx.features.content_type_gating.partitions.get_course_masquerade',
            return_value=mock_course_masquerade
        ), patch(
            'crum.get_current_request',
            return_value=mock_request
        ):
            fragment = partition.access_denied_fragment(mock_block, global_staff, GroupFactory(), 'test_allowed_group')

        self.assertIsNotNone(fragment)
예제 #6
0
    def test_missing_enrollment_mode(self):
        """
        Test that an enrollment mode that is no longer registered is displayed as 'deleted',
        regardless of the number of current enrollment modes in the course.
        """
        # Only 1 mode (the default) exists, so nothing initially shows in the visibility view.
        self.verify_visibility_view_contains(
            self.video_location,
            [self.NO_CONTENT_OR_ENROLLMENT_GROUPS, self.NO_CONTENT_ENROLLMENT_TRACK_ENABLED]
        )
        self.verify_visibility_view_does_not_contain(
            self.video_location, [self.ENROLLMENT_GROUPS_TITLE, self.GROUP_NO_LONGER_EXISTS]
        )

        # Set group_access to reference a missing mode.
        self.set_group_access(self.video_location, ['10'], ENROLLMENT_TRACK_PARTITION_ID)
        self.verify_visibility_view_contains(
            self.video_location, [self.ENROLLMENT_GROUPS_TITLE, self.GROUP_NO_LONGER_EXISTS]
        )

        # Add 2 explicit enrollment modes.
        CourseModeFactory.create(course_id=self.course.id, mode_slug='audit')
        CourseModeFactory.create(course_id=self.course.id, mode_slug='verified')
        self.verify_visibility_view_contains(
            self.video_location,
            [self.ENROLLMENT_GROUPS_TITLE, 'audit course', 'verified course', self.GROUP_NO_LONGER_EXISTS]
        )
    def setup_course_and_user(
            self,
            days_till_start=1,
            days_till_end=14,
            days_till_upgrade_deadline=4,
            enrollment_mode=CourseMode.VERIFIED,
            days_till_verification_deadline=14,
            verification_status=None,
    ):
        """Set up the course and user for this test."""
        now = datetime.now(pytz.UTC)
        self.course = CourseFactory.create(  # pylint: disable=attribute-defined-outside-init
            start=now + timedelta(days=days_till_start),
            end=now + timedelta(days=days_till_end),
        )
        self.user = UserFactory.create()  # pylint: disable=attribute-defined-outside-init

        if enrollment_mode is not None and days_till_upgrade_deadline is not None:
            CourseModeFactory.create(
                course_id=self.course.id,
                mode_slug=enrollment_mode,
                expiration_datetime=now + timedelta(days=days_till_upgrade_deadline)
            )
            CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user, mode=enrollment_mode)
        else:
            CourseEnrollmentFactory.create(course_id=self.course.id, user=self.user)

        if days_till_verification_deadline is not None:
            VerificationDeadline.objects.create(
                course_key=self.course.id,
                deadline=now + timedelta(days=days_till_verification_deadline)
            )

        if verification_status is not None:
            SoftwareSecurePhotoVerificationFactory.create(user=self.user, status=verification_status)
예제 #8
0
    def test_choose_mode_audit_enroll_on_get(self):
        """
        Confirms that the learner will be enrolled in Audit track if it is the only possible option
        """
        self.mock_enterprise_learner_api()
        self.mock_enterprise_course_enrollment_get_api()
        # Create the course mode
        audit_mode = 'audit'
        CourseModeFactory.create(mode_slug=audit_mode, course_id=self.course.id, min_price=0)

        # Assert learner is not enrolled in Audit track pre-POST
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertIsNone(mode)
        self.assertIsNone(is_active)

        # Choose the audit mode (POST request)
        choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(choose_track_url)

        # Assert learner is enrolled in Audit track and sent to the dashboard
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertEquals(mode, audit_mode)
        self.assertTrue(is_active)

        redirect_url = reverse('dashboard')
        self.assertRedirects(response, redirect_url)
예제 #9
0
    def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect):
        # Create the course modes
        for mode in ('audit', 'honor', 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        # Enroll the user in the test course
        if enrollment_mode is not None:
            CourseEnrollmentFactory(
                is_active=is_active,
                mode=enrollment_mode,
                course_id=self.course.id,
                user=self.user
            )

        self.mock_enterprise_learner_api()

        # Configure whether we're upgrading or not
        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)

        # Check whether we were correctly redirected
        if redirect:
            self.assertRedirects(response, reverse('dashboard'))
        else:
            self.assertEquals(response.status_code, 200)
예제 #10
0
    def test_expired_course_in_holdback(self):
        """
        Ensure that a user accessing an expired course that is in the holdback
        does not get redirected to the student dashboard, not a 404.
        """
        CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2010, 1, 1))

        course = CourseFactory.create(start=THREE_YEARS_AGO)
        url = course_home_url(course)

        for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]:
            CourseModeFactory.create(course_id=course.id, mode_slug=mode)

        ExperimentKeyValue.objects.create(
            experiment_id=EXPERIMENT_ID,
            key="content_type_gating_holdback_percentage",
            value="100"
        )

        # assert that an if an expired audit user in the holdback tries to access the course
        # they are not redirected to the dashboard
        audit_user = UserFactory(password=self.TEST_PASSWORD)
        self.client.login(username=audit_user.username, password=self.TEST_PASSWORD)
        audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT)
        ScheduleFactory(start=THREE_YEARS_AGO, enrollment=audit_enrollment)

        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)
    def test_transform_with_content_gating_partition(self):
        self.setup_partitions_and_course()
        CourseModeFactory.create(course_id=self.course.id, mode_slug='audit')
        CourseModeFactory.create(course_id=self.course.id, mode_slug='verified')
        ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        partition = create_content_gating_partition(self.course)
        self.user_partitions.append(partition)
        cohort = self.partition_cohorts[0][1]
        add_user_to_cohort(cohort, self.user.username)

        with patch(
            'lms.djangoapps.course_blocks.transformers.user_partitions.get_partition_from_id',
            return_value=partition
        ), patch(
            'lms.djangoapps.course_blocks.transformers.user_partitions._MergedGroupAccess.get_allowed_groups',
            return_value={51: set([])}
        ):
            trans_block_structure = get_course_blocks(
                self.user,
                self.course.location,
                self.transformers,
            )
            xblocks_denial_reason = [trans_block_structure.get_xblock_field(b, 'authorization_denial_reason')
                                     for b in trans_block_structure.get_block_keys()]
            self.assertSetEqual(set(xblocks_denial_reason), set([u'Feature-based Enrollments']))
예제 #12
0
    def setUp(self):
        super(TestProfEdVerification, self).setUp()

        self.user = UserFactory.create(username="******", password="******")
        self.client.login(username="******", password="******")
        course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
        self.course_key = course.id
        CourseModeFactory.create(
            mode_slug="professional",
            course_id=self.course_key,
            min_price=self.MIN_PRICE,
            suggested_prices=''
        )
        purchase_workflow = "?purchase_workflow=single"
        self.urls = {
            'course_modes_choose': reverse(
                'course_modes_choose',
                args=[unicode(self.course_key)]
            ),

            'verify_student_start_flow': reverse(
                'verify_student_start_flow',
                args=[unicode(self.course_key)]
            ) + purchase_workflow,
        }
예제 #13
0
    def test_certificate_footer_data(self):
        """
        Test that get_certificate_footer_context from lms.djangoapps.certificates api returns
        data customized according to site branding.
        """
        # Generate certificates for the course
        CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug=CourseMode.HONOR)
        data = certs_api.get_certificate_footer_context()

        # Make sure there are not unexpected keys in dict returned by 'get_certificate_footer_context'
        self.assertItemsEqual(
            data.keys(),
            ['company_about_url', 'company_privacy_url', 'company_tos_url']
        )
        self.assertIn(
            self.configuration['urls']['ABOUT'],
            data['company_about_url']
        )
        self.assertIn(
            self.configuration['urls']['PRIVACY'],
            data['company_privacy_url']
        )
        self.assertIn(
            self.configuration['urls']['TOS_AND_HONOR'],
            data['company_tos_url']
        )
예제 #14
0
    def test_suggested_prices(self, price_list):

        # Create the course modes
        for mode in ('audit', 'honor'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        CourseModeFactory.create(
            mode_slug='verified',
            course_id=self.course.id,
            suggested_prices=price_list
        )

        # Enroll the user in the test course to emulate
        # automatic enrollment
        CourseEnrollmentFactory(
            is_active=True,
            course_id=self.course.id,
            user=self.user
        )

        self.mock_enterprise_learner_api()

        # Verify that the prices render correctly
        response = self.client.get(
            reverse('course_modes_choose', args=[unicode(self.course.id)]),
            follow=False,
        )

        self.assertEquals(response.status_code, 200)
예제 #15
0
 def _create_course(self):
     course = CourseFactory.create(run='test', display_name='test')
     CourseModeFactory.create(course_id=course.id, mode_slug='audit')
     CourseModeFactory.create(course_id=course.id, mode_slug='verified')
     blocks_dict = {}
     with self.store.bulk_operations(course.id):
         blocks_dict['chapter'] = ItemFactory.create(
             parent=course,
             category='chapter',
             display_name='Week 1'
         )
         blocks_dict['sequential'] = ItemFactory.create(
             parent=blocks_dict['chapter'],
             category='sequential',
             display_name='Lesson 1'
         )
         blocks_dict['vertical'] = ItemFactory.create(
             parent=blocks_dict['sequential'],
             category='vertical',
             display_name='Lesson 1 Vertical - Unit 1'
         )
     return {
         'course': course,
         'blocks': blocks_dict,
     }
예제 #16
0
    def test_choose_mode_audit_enroll_on_post(self):
        audit_mode = 'audit'
        # Create the course modes
        for mode in (audit_mode, 'verified'):
            min_price = 0 if mode in [audit_mode] else 1
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price)

        # Assert learner is not enrolled in Audit track pre-POST
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertIsNone(mode)
        self.assertIsNone(is_active)

        # Choose the audit mode (POST request)
        choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)])
        self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[audit_mode])

        # Assert learner is enrolled in Audit track post-POST
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertEqual(mode, audit_mode)
        self.assertTrue(is_active)

        # Unenroll learner from Audit track and confirm the enrollment record is now 'inactive'
        CourseEnrollment.unenroll(self.user, self.course.id)
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertEqual(mode, audit_mode)
        self.assertFalse(is_active)

        # Choose the audit mode again
        self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[audit_mode])

        # Assert learner is again enrolled in Audit track post-POST-POST
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertEqual(mode, audit_mode)
        self.assertTrue(is_active)
예제 #17
0
    def test_unpublished_sessions_for_entitlement_when_enrolled(self, mock_get_edx_api_data):
        """
        Test unpublished course runs are part of visible session entitlements when the user
        is enrolled.
        """
        catalog_course_run = CourseRunFactory.create(status=COURSE_UNPUBLISHED)
        catalog_course = CourseFactory(course_runs=[catalog_course_run])
        mock_get_edx_api_data.return_value = catalog_course
        course_key = CourseKey.from_string(catalog_course_run.get('key'))
        course_overview = CourseOverviewFactory.create(id=course_key, start=self.tomorrow)
        CourseModeFactory.create(
            mode_slug=CourseMode.VERIFIED,
            min_price=100,
            course_id=course_overview.id,
            expiration_datetime=now() - timedelta(days=1)
        )
        course_enrollment = CourseEnrollmentFactory(
            user=self.user, course_id=unicode(course_overview.id), mode=CourseMode.VERIFIED
        )
        entitlement = CourseEntitlementFactory(
            user=self.user, enrollment_course_run=course_enrollment, mode=CourseMode.VERIFIED
        )

        session_entitlements = get_visible_sessions_for_entitlement(entitlement)
        self.assertEqual(session_entitlements, [catalog_course_run])
예제 #18
0
    def test_expired_course(self):
        """
        Ensure that a user accessing an expired course sees a redirect to
        the student dashboard, not a 404.
        """
        CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime(2010, 1, 1))
        course = CourseFactory.create(start=THREE_YEARS_AGO)
        url = course_home_url(course)

        for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]:
            CourseModeFactory.create(course_id=course.id, mode_slug=mode)

        # assert that an if an expired audit user tries to access the course they are redirected to the dashboard
        audit_user = UserFactory(password=self.TEST_PASSWORD)
        self.client.login(username=audit_user.username, password=self.TEST_PASSWORD)
        audit_enrollment = CourseEnrollment.enroll(audit_user, course.id, mode=CourseMode.AUDIT)
        ScheduleFactory(start=THREE_YEARS_AGO, enrollment=audit_enrollment)

        response = self.client.get(url)

        expiration_date = strftime_localized(course.start + timedelta(weeks=4), 'SHORT_DATE')
        expected_params = QueryDict(mutable=True)
        course_name = CourseOverview.get_from_id(course.id).display_name_with_default
        expected_params['access_response_error'] = 'Access to {run} expired on {expiration_date}'.format(
            run=course_name,
            expiration_date=expiration_date
        )
        expected_url = '{url}?{params}'.format(
            url=reverse('dashboard'),
            params=expected_params.urlencode()
        )
        self.assertRedirects(response, expected_url)
예제 #19
0
    def test_redirect_to_dashboard(self, is_active, enrollment_mode, redirect, has_started):
        # Configure whether course has started
        # If it has go to course home instead of dashboard
        course = self.course_that_started if has_started else self.course
        # Create the course modes
        for mode in ('audit', 'honor', 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=course.id)

        # Enroll the user in the test course
        if enrollment_mode is not None:
            CourseEnrollmentFactory(
                is_active=is_active,
                mode=enrollment_mode,
                course_id=course.id,
                user=self.user
            )

        # Configure whether we're upgrading or not
        url = reverse('course_modes_choose', args=[six.text_type(course.id)])
        response = self.client.get(url)

        # Check whether we were correctly redirected
        if redirect:
            if has_started:
                self.assertRedirects(
                    response, reverse('openedx.course_experience.course_home', kwargs={'course_id': course.id})
                )
            else:
                self.assertRedirects(response, reverse('dashboard'))
        else:
            self.assertEquals(response.status_code, 200)
예제 #20
0
    def test_score_recalculation_on_enrollment_update(self):
        """
        Test that an update in enrollment cause score recalculation.
        Note:
        Score recalculation task must be called with a delay of SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE
        """
        course_modes = ['verified', 'audit']

        for mode_slug in course_modes:
            CourseModeFactory.create(
                course_id=self.course.id,
                mode_slug=mode_slug,
                mode_display_name=mode_slug,
            )
        CourseEnrollment.enroll(self.user, self.course.id, mode="audit")

        local_task_args = dict(
            user_id=self.user.id,
            course_key=str(self.course.id)
        )

        with patch(
            'lms.djangoapps.grades.tasks.recalculate_course_and_subsection_grades_for_user.apply_async',
            return_value=None
        ) as mock_task_apply:
            CourseEnrollment.enroll(self.user, self.course.id, mode="verified")
            mock_task_apply.assert_called_once_with(
                countdown=SCORE_RECALCULATION_DELAY_ON_ENROLLMENT_UPDATE,
                kwargs=local_task_args
            )
예제 #21
0
    def test_acess_denied_fragment_for_null_request(self):
        """
        Verifies the access denied fragment is visible when HTTP request is not available.

        Given the HTTP request instance is None
        Then set the mobile_app context variable to False
        And the fragment should be created successfully
        """
        mock_request = None
        mock_course = Mock(id=self.course_key, user_partitions={})
        mock_block = Mock(scope_ids=Mock(usage_id=Mock(course_key=mock_course.id)))
        CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified')
        global_staff = GlobalStaffFactory.create()
        ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
        partition = create_content_gating_partition(mock_course)

        with patch(
            'crum.get_current_request',
            return_value=mock_request
        ), patch(
            'openedx.features.content_type_gating.partitions.ContentTypeGatingPartition._is_audit_enrollment',
            return_value=True
        ):
            fragment = partition.access_denied_fragment(mock_block, global_staff, GroupFactory(), 'test_allowed_group')

        self.assertIsNotNone(fragment)
예제 #22
0
    def test_enroll(self, course_modes, next_url, enrollment_mode):
        # Create the course modes (if any) required for this test case
        for mode_slug in course_modes:
            CourseModeFactory.create(
                course_id=self.course.id,
                mode_slug=mode_slug,
                mode_display_name=mode_slug,
            )

        # Reverse the expected next URL, if one is provided
        # (otherwise, use an empty string, which the JavaScript client
        # interprets as a redirect to the dashboard)
        full_url = (
            reverse(next_url, kwargs={'course_id': unicode(self.course.id)})
            if next_url else next_url
        )

        # Enroll in the course and verify the URL we get sent to
        resp = self._change_enrollment('enroll')
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.content, full_url)

        # If we're not expecting to be enrolled, verify that this is the case
        if enrollment_mode is None:
            self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id))

        # Otherwise, verify that we're enrolled with the expected course mode
        else:
            self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
            course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
            self.assertTrue(is_active)
            self.assertEqual(course_mode, enrollment_mode)
예제 #23
0
    def test_linked_in_add_to_profile_btn_not_appearing_without_config(self):
        # Without linked-in config don't show Add Certificate to LinkedIn button
        self.client.login(username="******", password="******")

        CourseModeFactory.create(
            course_id=self.course.id,
            mode_slug='verified',
            mode_display_name='verified',
            expiration_datetime=datetime.now(pytz.UTC) - timedelta(days=1)
        )

        CourseEnrollment.enroll(self.user, self.course.id, mode='honor')

        self.course.start = datetime.now(pytz.UTC) - timedelta(days=2)
        self.course.end = datetime.now(pytz.UTC) - timedelta(days=1)
        self.course.display_name = u"Omega"
        self.course = self.update_course(self.course, self.user.id)

        download_url = 'www.edx.org'
        GeneratedCertificateFactory.create(
            user=self.user,
            course_id=self.course.id,
            status=CertificateStatuses.downloadable,
            mode='honor',
            grade='67',
            download_url=download_url
        )
        response = self.client.get(reverse('dashboard'))

        self.assertEquals(response.status_code, 200)
        self.assertNotIn('Add Certificate to LinkedIn', response.content)

        response_url = 'http://www.linkedin.com/profile/add?_ed='
        self.assertNotContains(response, escape(response_url))
    def setUp(self):
        super(ChangeEnrollmentTests, self).setUp()
        self.course = CourseFactory.create()
        self.audit_mode = CourseModeFactory.create(
            course_id=self.course.id,
            mode_slug='audit',
            mode_display_name='Audit',
        )
        self.honor_mode = CourseModeFactory.create(
            course_id=self.course.id,
            mode_slug='honor',
            mode_display_name='Honor',
        )

        self.user_info = [
            ('amy', '*****@*****.**', 'password'),
            ('rory', '*****@*****.**', 'password'),
            ('river', '*****@*****.**', 'password')
        ]
        self.enrollments = []
        self.users = []
        for username, email, password in self.user_info:
            user = UserFactory.create(username=username, email=email, password=password)
            self.users.append(user)
            self.enrollments.append(CourseEnrollment.enroll(user, self.course.id, mode='audit'))
예제 #25
0
    def _create_course(cls, run, display_name, modes, component_types):
        """
        Helper method to create a course
        Arguments:
            run (str): name of course run
            display_name (str): display name of course
            modes (list of str): list of modes/tracks this course should have
            component_types (list of str): list of problem types this course should have
        Returns:
             (dict): {
                'course': (CourseDescriptorWithMixins): course definition
                'blocks': (dict) {
                    'block_category_1': XBlock representing that block,
                    'block_category_2': XBlock representing that block,
                    ....
             }
        """
        start_date = timezone.now() - timedelta(weeks=1)
        course = CourseFactory.create(run=run, display_name=display_name, start=start_date)

        for mode in modes:
            CourseModeFactory.create(course_id=course.id, mode_slug=mode)

        with cls.store.bulk_operations(course.id):
            blocks_dict = {}
            chapter = ItemFactory.create(
                parent=course,
                display_name='Overview',
            )
            blocks_dict['chapter'] = ItemFactory.create(
                parent=course,
                category='chapter',
                display_name='Week 1',
            )
            blocks_dict['sequential'] = ItemFactory.create(
                parent=chapter,
                category='sequential',
                display_name='Lesson 1',
            )
            blocks_dict['vertical'] = ItemFactory.create(
                parent=blocks_dict['sequential'],
                category='vertical',
                display_name='Lesson 1 Vertical - Unit 1',
            )

            for component_type in component_types:
                block = ItemFactory.create(
                    parent=blocks_dict['vertical'],
                    category=component_type,
                    display_name=component_type,
                    graded=True,
                    metadata={} if (component_type == 'html' or len(modes) == 1) else METADATA
                )
                blocks_dict[component_type] = block

            return {
                'course': course,
                'blocks': blocks_dict,
            }
예제 #26
0
 def setUp(self):
     super(DashboardTestsWithSiteOverrides, self).setUp()
     self.org = 'fakeX'
     self.course = CourseFactory.create(org=self.org)
     self.user = UserFactory.create(username='******', email='*****@*****.**', password='******')
     CourseModeFactory.create(mode_slug='no-id-professional', course_id=self.course.id)
     CourseEnrollment.enroll(self.user, self.course.location.course_key, mode='no-id-professional')
     cache.clear()
예제 #27
0
 def add_to_cart(self):
     """
     Adds content to self.user's cart
     """
     course = CourseFactory.create(org='MITx', number='999', display_name='Robot Super Course')
     CourseModeFactory.create(course_id=course.id)
     cart = Order.get_cart_for_user(self.user)
     PaidCourseRegistration.add_to_order(cart, course.id)
예제 #28
0
 def _create_course_modes(self, course_modes, course=None):
     """Create the course modes required for a test. """
     course_id = course.id if course else self.course.id
     for mode_slug in course_modes:
         CourseModeFactory.create(
             course_id=course_id,
             mode_slug=mode_slug,
             mode_display_name=mode_slug,
         )
예제 #29
0
    def test_unsupported_enrollment_mode_failure(self):
        # Create the supported course modes
        for mode in ('honor', 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        # Choose an unsupported mode (POST request)
        choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)])
        response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['unsupported'])

        self.assertEqual(400, response.status_code)
예제 #30
0
 def _enrollment_with_complete_course(self, enrollment_mode):
     """"Dry method for course enrollment."""
     CourseModeFactory.create(
         course_id=self.course.id,
         mode_slug='verified',
         mode_display_name='Verified',
         expiration_datetime=datetime.now(pytz.UTC) + timedelta(days=1)
     )
     enrollment = CourseEnrollment.enroll(self.user, self.course.id, mode=enrollment_mode)
     return complete_course_mode_info(self.course.id, enrollment)
    def setUp(self):
        super(TestProfEdVerification, self).setUp()

        self.user = UserFactory.create(username="******", password="******")
        self.client.login(username="******", password="******")
        course = CourseFactory.create(org='Robot',
                                      number='999',
                                      display_name='Test Course')
        self.course_key = course.id
        CourseModeFactory.create(mode_slug="professional",
                                 course_id=self.course_key,
                                 min_price=self.MIN_PRICE,
                                 suggested_prices='')
        purchase_workflow = "?purchase_workflow=single"
        self.urls = {
            'course_modes_choose':
            reverse('course_modes_choose',
                    args=[six.text_type(self.course_key)]),
            'verify_student_start_flow':
            reverse('verify_student_start_flow',
                    args=[six.text_type(self.course_key)]) + purchase_workflow,
        }
예제 #32
0
    def test_credit_upsell_message(self, available_modes, show_upsell):
        # Create the course modes
        for mode in available_modes:
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        self.mock_enterprise_learner_api()
        # Create a service user and log in.
        UserFactory.create(
            username='******',
            email="*****@*****.**",
            password="******",
        )

        # Check whether credit upsell is shown on the page
        # This should *only* be shown when a credit mode is available
        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)

        if show_upsell:
            self.assertContains(response, "Credit")
        else:
            self.assertNotContains(response, "Credit")
    def test_donate_button_honor_with_price(self):
        # Enable the enrollment success message and donations
        self._configure_message_timeout(10000)
        DonationConfiguration(enabled=True).save()

        # Create a white-label course mode
        # (honor mode with a price set)
        CourseModeFactory(mode_slug="honor", course_id=self.course.id, min_price=100)

        # Check that the donate button is NOT displayed
        self.client.login(username=self.student.username, password=self.PASSWORD)
        response = self.client.get(reverse("dashboard"))
        self.assertNotContains(response, "donate-container")
예제 #34
0
    def test_hide_nav(self):
        # Create the course modes
        for mode in ["honor", "verified"]:
            CourseModeFactory(mode_slug=mode, course_id=self.course.id)

        # Load the track selection page
        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)

        # Verify that the header navigation links are hidden for the edx.org version
        self.assertNotContains(response, "How it Works")
        self.assertNotContains(response, "Find courses")
        self.assertNotContains(response, "Schools & Partners")
예제 #35
0
    def test_congrats_on_enrollment_message(self, create_enrollment):
        # Create the course mode
        CourseModeFactory.create(mode_slug='verified',
                                 course_id=self.course.id)

        if create_enrollment:
            CourseEnrollmentFactory(is_active=True,
                                    course_id=self.course.id,
                                    user=self.user)

        # Check whether congratulations message is shown on the page
        # This should *only* be shown when an enrollment exists
        url = reverse('course_modes_choose',
                      args=[six.text_type(self.course.id)])
        response = self.client.get(url)

        if create_enrollment:
            self.assertContains(response,
                                "Congratulations!  You are now enrolled in")
        else:
            self.assertNotContains(
                response, "Congratulations!  You are now enrolled in")
예제 #36
0
    def test_enterprise_learner_context_with_multiple_organizations(self):
        """
        Test: Track selection page should show the enterprise context message with multiple organization names
        if user belongs to the Enterprise.
        """
        # Create the course modes
        for mode in ('audit', 'honor', 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        catalog_integration = self.create_catalog_integration()
        UserFactory(username=catalog_integration.service_username)
        self.mock_enterprise_learner_api()
        self.mock_course_discovery_api_for_catalog_contains(
            catalog_id=1, course_run_ids=[str(self.course.id)])

        # Creating organization
        for i in xrange(2):
            test_organization_data = {
                'name': 'test organization ' + str(i),
                'short_name': 'test_organization_' + str(i),
                'description': 'Test Organization Description',
                'active': True,
                'logo': '/logo_test1.png/'
            }
            test_org = organizations_api.add_organization(
                organization_data=test_organization_data)
            organizations_api.add_organization_course(
                organization_data=test_org, course_id=unicode(self.course.id))

        # User visits the track selection page directly without ever enrolling
        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)
        self.assertEquals(response.status_code, 200)
        self.assertContains(
            response,
            'Welcome, {username}! You are about to enroll in {course_name}, from test organization 0 and '
            'test organization 1, sponsored by TestShib. Please select your enrollment information below.'
            .format(username=self.user.username,
                    course_name=self.course.display_name_with_default_escaped))
예제 #37
0
    def _check_verification_status_off(self, mode, value):
        """
        Check that the css class and the status message are not in the dashboard html.
        """
        CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
        CourseEnrollment.enroll(self.user, self.course.location.course_key, mode=mode)

        if mode == 'verified':
            # Simulate a successful verification attempt
            attempt = SoftwareSecurePhotoVerification.objects.create(user=self.user)
            attempt.mark_ready()
            attempt.submit()
            attempt.approve()

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

        if mode == 'audit':
            # Audit mode does not have a banner.  Assert no banner element.
            self.assertEqual(pq(response.content)(".sts-enrollment").length, 0)
        else:
            self.assertNotContains(response, "class=\"course {0}\"".format(mode))
            self.assertNotContains(response, value)
예제 #38
0
    def test_generate_example_certs_with_verified_mode(self):
        # Create verified and honor modes for the course
        CourseModeFactory.create(course_id=self.COURSE_KEY, mode_slug='honor')
        CourseModeFactory.create(course_id=self.COURSE_KEY,
                                 mode_slug='verified')

        # Generate certificates for the course
        with self._mock_xqueue() as mock_queue:
            certs_api.generate_example_certificates(self.COURSE_KEY)

        # Verify that the appropriate certs were added to the queue
        self._assert_certs_in_queue(mock_queue, 2)

        # Verify that the certificate status is "started"
        self._assert_cert_status(
            {
                'description': 'verified',
                'status': 'started'
            }, {
                'description': 'honor',
                'status': 'started'
            })
예제 #39
0
    def setUp(self):
        super(EntitlementViewSetTest, self).setUp()
        self.user = UserFactory(is_staff=True)
        self.client.login(username=self.user.username, password=TEST_PASSWORD)
        self.course = CourseFactory()
        self.course_mode = CourseModeFactory(
            course_id=self.course.id,
            mode_slug=CourseMode.VERIFIED,
            # This must be in the future to ensure it is returned by downstream code.
            expiration_datetime=now() + timedelta(days=1))

        self.entitlements_list_url = reverse(
            'entitlements_api:v1:entitlements-list')
예제 #40
0
    def test_expired_course(self):
        """
        Ensure that a user accessing an expired course sees a redirect to
        the student dashboard, not a 404.
        """
        CourseDurationLimitConfig.objects.create(enabled=True,
                                                 enabled_as_of=datetime(
                                                     2010, 1, 1))
        course = CourseFactory.create(start=THREE_YEARS_AGO)
        url = course_home_url(course)

        for mode in [CourseMode.AUDIT, CourseMode.VERIFIED]:
            CourseModeFactory.create(course_id=course.id, mode_slug=mode)

        # assert that an if an expired audit user tries to access the course they are redirected to the dashboard
        audit_user = UserFactory(password=self.TEST_PASSWORD)
        self.client.login(username=audit_user.username,
                          password=self.TEST_PASSWORD)
        audit_enrollment = CourseEnrollment.enroll(audit_user,
                                                   course.id,
                                                   mode=CourseMode.AUDIT)
        audit_enrollment.created = THREE_YEARS_AGO + timedelta(days=1)
        audit_enrollment.save()
        ScheduleFactory(enrollment=audit_enrollment)

        response = self.client.get(url)

        expiration_date = strftime_localized(
            course.start + timedelta(weeks=4) + timedelta(days=1),
            u'%b %-d, %Y')
        expected_params = QueryDict(mutable=True)
        course_name = CourseOverview.get_from_id(
            course.id).display_name_with_default
        expected_params[
            'access_response_error'] = u'Access to {run} expired on {expiration_date}'.format(
                run=course_name, expiration_date=expiration_date)
        expected_url = '{url}?{params}'.format(
            url=reverse('dashboard'), params=expected_params.urlencode())
        self.assertRedirects(response, expected_url)
예제 #41
0
    def test_course_closed(self):
        for mode in ["honor", "verified"]:
            CourseModeFactory(mode_slug=mode, course_id=self.course.id)

        self.course.enrollment_end = datetime(2015, 01, 01)
        modulestore().update_item(self.course, self.user.id)

        url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.get(url)
        # URL-encoded version of 1/1/15, 12:00 AM
        redirect_url = reverse(
            'dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM'
        self.assertRedirects(response, redirect_url)
예제 #42
0
    def test_choose_mode_redirect(self, course_mode, expected_redirect):
        # Create the course modes
        for mode in ('audit', 'honor', 'verified'):
            min_price = 0 if mode in ["honor", "audit"] else 1
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price)

        # Choose the mode (POST request)
        choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[course_mode])

        # Verify the redirect
        if expected_redirect == 'dashboard':
            redirect_url = reverse('dashboard')
        elif expected_redirect == 'start-flow':
            redirect_url = reverse(
                'verify_student_start_flow',
                kwargs={'course_id': unicode(self.course.id)}
            )
        else:
            self.fail("Must provide a valid redirect URL name")

        self.assertRedirects(response, redirect_url)
예제 #43
0
    def setUp(self):
        """ Create a course and user, then log in. Also creates a course mode."""
        # This function is a simplified version of test_views.EnrollmentTest.setUp

        super(EnrollmentEmailNotificationTest, self).setUp()

        # Pass emit_signals when creating the course so it would be cached
        # as a CourseOverview.
        self.course = CourseFactory.create(emit_signals=True)

        self.user = UserFactory.create(
            username=self.USERNAME,
            email=self.EMAIL,
            password=self.PASSWORD,
        )
        self.client.login(username=self.USERNAME, password=self.PASSWORD)

        CourseModeFactory.create(
            course_id=self.course.id,
            mode_slug=CourseMode.DEFAULT_MODE_SLUG,
            mode_display_name=CourseMode.DEFAULT_MODE_SLUG,
        )
예제 #44
0
    def setUp(self):
        super(SupportViewEnrollmentsTests, self).setUp()
        SupportStaffRole().add_users(self.user)

        self.course = CourseFactory(display_name=u'teꜱᴛ')
        self.student = UserFactory.create(username='******', email='*****@*****.**', password='******')

        for mode in (
                CourseMode.AUDIT, CourseMode.PROFESSIONAL, CourseMode.CREDIT_MODE,
                CourseMode.NO_ID_PROFESSIONAL_MODE, CourseMode.VERIFIED, CourseMode.HONOR
        ):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        self.verification_deadline = VerificationDeadline(
            course_key=self.course.id,
            deadline=datetime.now(UTC) + timedelta(days=365)
        )
        self.verification_deadline.save()

        CourseEnrollmentFactory.create(mode=CourseMode.AUDIT, user=self.student, course_id=self.course.id)

        self.url = reverse('support:enrollment_list', kwargs={'username_or_email': self.student.username})
예제 #45
0
    def test_no_id_redirect(self):
        # Create the course modes
        CourseModeFactory.create(mode_slug=CourseMode.NO_ID_PROFESSIONAL_MODE,
                                 course_id=self.course.id,
                                 min_price=100)

        # Enroll the user in the test course
        CourseEnrollmentFactory(is_active=False,
                                mode=CourseMode.NO_ID_PROFESSIONAL_MODE,
                                course_id=self.course.id,
                                user=self.user)

        # Configure whether we're upgrading or not
        url = reverse('course_modes_choose',
                      args=[six.text_type(self.course.id)])
        response = self.client.get(url)
        # Check whether we were correctly redirected
        purchase_workflow = "?purchase_workflow=single"
        start_flow_url = reverse('verify_student_start_flow',
                                 args=[six.text_type(self.course.id)
                                       ]) + purchase_workflow
        self.assertRedirects(response, start_flow_url)
예제 #46
0
def create_self_paced_course_run(days_till_start=1, org_id=None):
    """ Create a new course run and course modes.

    All date-related arguments are relative to the current date-time (now) unless otherwise specified.

    Both audit and verified `CourseMode` objects will be created for the course run.

    Arguments:
        days_till_start (int): Number of days until the course starts.
        org_id (string): String org id to assign the course to (default: None; use CourseFactory default)
    """
    now = datetime.now(utc)
    course = CourseFactory.create(start=now + timedelta(days=days_till_start),
                                  self_paced=True,
                                  org=org_id if org_id else 'TestedX')

    CourseModeFactory(course_id=course.id, mode_slug=CourseMode.AUDIT)
    CourseModeFactory(course_id=course.id,
                      mode_slug=CourseMode.VERIFIED,
                      expiration_datetime=now + timedelta(days=100))

    return course
    def handle(self, *args, **options):
        courses = modulestore().get_courses()

        # Find the largest auto-generated course, and pick the next sequence id to generate the next
        # course with.
        max_org_sequence_id = max([0] + [int(course.org[4:]) for course in courses if course.org.startswith('org.')])

        XMODULE_FACTORY_LOCK.enable()
        CourseFactory.reset_sequence(max_org_sequence_id + 1, force=True)
        course = CourseFactory.create(
            start=datetime.datetime.today() - datetime.timedelta(days=30),
            end=datetime.datetime.today() + datetime.timedelta(days=30),
            number=factory.Sequence('schedules_test_course_{}'.format),
            display_name=factory.Sequence(u'Schedules Test Course {}'.format),
        )
        XMODULE_FACTORY_LOCK.disable()
        course_overview = CourseOverview.load_from_module_store(course.id)
        CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.AUDIT)
        CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.VERIFIED)
        CourseDurationLimitExpirySchedule.create_batch(20, enrollment__course=course_overview)

        ScheduleConfigFactory.create(site=Site.objects.get(name='example.com'))
    def test_donate_button(self, course_modes, enrollment_mode, show_donate):
        # Enable the enrollment success message
        self._configure_message_timeout(10000)

        # Enable donations
        DonationConfiguration(enabled=True).save()

        # Create the course mode(s)
        for mode, min_price in course_modes:
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price)

        self.enrollment.mode = enrollment_mode
        self.enrollment.save()

        # Check that the donate button is or is not displayed
        self.client.login(username=self.student.username, password=self.PASSWORD)
        response = self.client.get(reverse("dashboard"))

        if show_donate:
            self.assertContains(response, "donate-container")
        else:
            self.assertNotContains(response, "donate-container")
예제 #49
0
    def setUp(self):
        super(FinancialAssistanceToolTest, self).setUp()

        self.course_financial_mode = CourseModeFactory(
            course_id=self.course.id,
            mode_slug=CourseMode.VERIFIED,
            expiration_datetime=self.now + datetime.timedelta(days=1),
        )
        DynamicUpgradeDeadlineConfiguration.objects.create(enabled=True)

        self.request = RequestFactory().request()
        crum.set_current_request(self.request)
        self.addCleanup(crum.set_current_request, None)

        # baseline course enrollment, future upgrade deadline
        self.enrollment = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.AUDIT,
            course=self.course_overview,
        )
        self.request.user = self.enrollment.user

        # enrollment where learner has upgraded
        self.enrollment_upgraded = CourseEnrollmentFactory(
            course_id=self.course.id,
            mode=CourseMode.VERIFIED,
            course=self.course_overview,
        )

        # course enrollment for mock: upgrade deadline in the past
        self.enrollment_deadline_past = self.enrollment
        self.enrollment_deadline_past.course_upgrade_deadline = self.now - datetime.timedelta(
            days=1)
        self.enrollment_deadline_past.save()

        # course enrollment for mock: no upgrade deadline
        self.enrollment_deadline_missing = self.enrollment
        self.enrollment_deadline_missing.course_upgrade_deadline = None
        self.enrollment_deadline_missing.save()
예제 #50
0
    def test_ended_course(self):
        course = CourseFactory.create(
            start=now() - timedelta(days=60),
            end=now() - timedelta(days=30),
            run='test',
            display_name='test',
        )
        CourseModeFactory.create(
            mode_slug=CourseMode.VERIFIED,
            course_id=course.id,
            min_price=10,
            sku=six.text_type(uuid4().hex)
        )

        response = self.client.get(self.url, {'course_id': course.id})
        self.assertEqual(response.status_code, 200)
        expected = {
            'show_upsell': False,
            'upsell_flag': True,
            'course_running': False,
        }
        self.assertEqual(response.data, expected)
예제 #51
0
    def setUp(self):
        super(TestReverifyService, self).setUp()

        self.user = UserFactory.create(username="******", password="******")
        course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
        self.course_key = course.id
        CourseModeFactory(
            mode_slug="verified",
            course_id=self.course_key,
            min_price=100,
            suggested_prices=''
        )
        self.item = ItemFactory.create(parent=course, category='chapter', display_name='Test Section')
예제 #52
0
def create_course_run(
    days_till_start=1,
    days_till_end=14,
    days_till_upgrade_deadline=4,
    days_till_verification_deadline=14,
):
    """ Create a new course run and course modes.

    All date-related arguments are relative to the current date-time (now) unless otherwise specified.

    Both audit and verified `CourseMode` objects will be created for the course run.

    Arguments:
        days_till_end (int): Number of days until the course ends.
        days_till_start (int): Number of days until the course starts.
        days_till_upgrade_deadline (int): Number of days until the course run's upgrade deadline.
        days_till_verification_deadline (int): Number of days until the course run's verification deadline. If this
            value is set to `None` no deadline will be verification deadline will be created.
    """
    now = datetime.now(utc)
    course = CourseFactory.create(start=now + timedelta(days=days_till_start))

    course.end = None
    if days_till_end is not None:
        course.end = now + timedelta(days=days_till_end)

    CourseModeFactory(course_id=course.id, mode_slug=CourseMode.AUDIT)
    CourseModeFactory(course_id=course.id,
                      mode_slug=CourseMode.VERIFIED,
                      expiration_datetime=now +
                      timedelta(days=days_till_upgrade_deadline))

    if days_till_verification_deadline is not None:
        VerificationDeadline.objects.create(
            course_key=course.id,
            deadline=now + timedelta(days=days_till_verification_deadline))

    return course
예제 #53
0
    def setup_course_and_user(
        self,
        days_till_start=1,
        days_till_end=14,
        days_till_upgrade_deadline=4,
        enrollment_mode=CourseMode.VERIFIED,
        days_till_verification_deadline=14,
        verification_status=None,
    ):
        """Set up the course and user for this test."""
        now = datetime.now(pytz.UTC)
        self.course = CourseFactory.create(  # pylint: disable=attribute-defined-outside-init
            start=now + timedelta(days=days_till_start),
            end=now + timedelta(days=days_till_end),
        )
        self.user = UserFactory.create()  # pylint: disable=attribute-defined-outside-init

        if enrollment_mode is not None and days_till_upgrade_deadline is not None:
            CourseModeFactory.create(
                course_id=self.course.id,
                mode_slug=enrollment_mode,
                expiration_datetime=now +
                timedelta(days=days_till_upgrade_deadline))
            CourseEnrollmentFactory.create(course_id=self.course.id,
                                           user=self.user,
                                           mode=enrollment_mode)
        else:
            CourseEnrollmentFactory.create(course_id=self.course.id,
                                           user=self.user)

        if days_till_verification_deadline is not None:
            VerificationDeadline.objects.create(
                course_key=self.course.id,
                deadline=now + timedelta(days=days_till_verification_deadline))

        if verification_status is not None:
            SoftwareSecurePhotoVerificationFactory.create(
                user=self.user, status=verification_status)
예제 #54
0
    def test_remember_donation_for_course(self):
        # Create the course modes
        CourseModeFactory.create(mode_slug='honor', course_id=self.course.id)
        CourseModeFactory.create(mode_slug='verified',
                                 course_id=self.course.id,
                                 min_price=1)

        # Choose the mode (POST request)
        choose_track_url = reverse('course_modes_choose',
                                   args=[unicode(self.course.id)])
        self.client.post(choose_track_url,
                         self.POST_PARAMS_FOR_COURSE_MODE['verified'])

        # Expect that the contribution amount is stored in the user's session
        self.assertIn('donation_for_course', self.client.session)
        self.assertIn(unicode(self.course.id),
                      self.client.session['donation_for_course'])

        actual_amount = self.client.session['donation_for_course'][unicode(
            self.course.id)]
        expected_amount = decimal.Decimal(
            self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution'])
        self.assertEqual(actual_amount, expected_amount)
예제 #55
0
    def test_suggested_prices(self, price_list):

        # Create the course modes
        for mode in ('audit', 'honor'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        CourseModeFactory.create(mode_slug='verified',
                                 course_id=self.course.id,
                                 suggested_prices=price_list)

        # Enroll the user in the test course to emulate
        # automatic enrollment
        CourseEnrollmentFactory(is_active=True,
                                course_id=self.course.id,
                                user=self.user)

        # Verify that the prices render correctly
        response = self.client.get(
            reverse('course_modes_choose', args=[unicode(self.course.id)]),
            follow=False,
        )

        self.assertEquals(response.status_code, 200)
예제 #56
0
    def _configure(self, mode, upgrade_deadline=None, verification_deadline=None):
        """Configure course modes and deadlines. """
        course_mode = CourseModeFactory.create(
            mode_slug=mode,
            mode_display_name=mode,
        )

        if upgrade_deadline is not None:
            course_mode.upgrade_deadline = upgrade_deadline
            course_mode.save()

        VerificationDeadline.set_deadline(self.course.id, verification_deadline)

        return CourseModeForm(instance=course_mode)
예제 #57
0
 def _admin_form(self, mode, upgrade_deadline=None):
     """Load the course mode admin form. """
     course_mode = CourseModeFactory.create(
         course_id=self.course.id,
         mode_slug=mode,
     )
     return CourseModeForm({
         "course_id": unicode(self.course.id),
         "mode_slug": mode,
         "mode_display_name": mode,
         "_expiration_datetime": upgrade_deadline,
         "currency": "usd",
         "min_price": 10,
     }, instance=course_mode)
예제 #58
0
    def test_successful_default_enrollment(self):
        self.mock_enterprise_learner_api()
        self.mock_enterprise_course_enrollment_get_api()
        # Create the course modes
        for mode in (CourseMode.DEFAULT_MODE_SLUG, 'verified'):
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        # Enroll the user in the default mode (honor) to emulate
        # automatic enrollment
        params = {
            'enrollment_action': 'enroll',
            'course_id': unicode(self.course.id)
        }
        self.client.post(reverse('change_enrollment'), params)

        # Explicitly select the honor mode (POST request)
        choose_track_url = reverse('course_modes_choose', args=[unicode(self.course.id)])
        self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[CourseMode.DEFAULT_MODE_SLUG])

        # Verify that the user's enrollment remains unchanged
        mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
        self.assertEqual(mode, CourseMode.DEFAULT_MODE_SLUG)
        self.assertEqual(is_active, True)
예제 #59
0
 def test_upgrade_deadline(self):
     """ The property should use either the CourseMode or related Schedule to determine the deadline. """
     course = CourseFactory(self_paced=True)
     course_mode = CourseModeFactory(
         course_id=course.id,
         mode_slug=CourseMode.VERIFIED,
         # This must be in the future to ensure it is returned by downstream code.
         expiration_datetime=datetime.datetime.now(pytz.UTC) +
         datetime.timedelta(days=1))
     enrollment = CourseEnrollmentFactory(course_id=course.id,
                                          mode=CourseMode.AUDIT)
     self.assertEqual(Schedule.objects.all().count(), 0)
     self.assertEqual(enrollment.upgrade_deadline,
                      course_mode.expiration_datetime)
예제 #60
0
    def test_certificate_info_in_response(self):
        """
        Test that certificate has been created and rendered properly with non-audit course mode.
        """
        CourseModeFactory.create(course_id=self.course.id,
                                 mode_slug='verified')
        response = self.client.ajax_post(
            self._url(), data=CERTIFICATE_JSON_WITH_SIGNATORIES)

        self.assertEqual(response.status_code, 201)

        # in html response
        result = self.client.get_html(self._url())
        self.assertIn('Test certificate', result.content)
        self.assertIn('Test description', result.content)

        # in JSON response
        response = self.client.get_json(self._url())
        data = json.loads(response.content.decode('utf-8'))
        self.assertEquals(len(data), 1)
        self.assertEqual(data[0]['name'], 'Test certificate')
        self.assertEqual(data[0]['description'], 'Test description')
        self.assertEqual(data[0]['version'], CERTIFICATE_SCHEMA_VERSION)