Ejemplo n.º 1
0
    def test_generate_example_certs(self):
        # Generate certificates for the course
        CourseModeFactory.create(course_id=self.COURSE_KEY,
                                 mode_slug=CourseMode.HONOR)
        with self._mock_xqueue() as mock_queue:
            generate_example_certificates(self.COURSE_KEY)

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

        # Verify that the certificate status is "started"
        self._assert_cert_status({'description': 'honor', 'status': 'started'})
    def test_generate_course_expired_message(self, offsets):
        now = timezone.now()
        schedule_offset, course_offset = offsets

        # Set a timezone and request, to test that the message looks at the user's setting
        request = RequestFactory().get('/')
        request.user = UserFactory()
        set_current_request(request)
        self.addCleanup(set_current_request, None)
        set_user_preference(request.user, 'time_zone', 'Asia/Tokyo')

        if schedule_offset is not None:
            schedule_upgrade_deadline = now + timedelta(days=schedule_offset)
        else:
            schedule_upgrade_deadline = None

        if course_offset is not None:
            course_upgrade_deadline = now + timedelta(days=course_offset)
        else:
            course_upgrade_deadline = None

        enrollment = CourseEnrollmentFactory.create(course=self.course)
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.VERIFIED,
            expiration_datetime=course_upgrade_deadline,
        )
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.AUDIT,
        )
        Schedule.objects.update(upgrade_deadline=schedule_upgrade_deadline)

        duration_limit_upgrade_deadline = get_user_course_expiration_date(
            enrollment.user, enrollment.course)
        assert duration_limit_upgrade_deadline is not None

        message = generate_course_expired_message(enrollment.user,
                                                  enrollment.course)

        self.assertDateInMessage(duration_limit_upgrade_deadline, message)
        assert 'data-timezone="Asia/Tokyo"' in message

        soft_upgradeable = schedule_upgrade_deadline is not None and now < schedule_upgrade_deadline
        upgradeable = course_upgrade_deadline is None or now < course_upgrade_deadline
        has_upgrade_deadline = course_upgrade_deadline is not None

        if upgradeable and soft_upgradeable:
            self.assertDateInMessage(schedule_upgrade_deadline, message)
        elif upgradeable and has_upgrade_deadline:
            self.assertDateInMessage(course_upgrade_deadline, message)
        else:
            assert 'Upgrade by' not in message
Ejemplo n.º 3
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=[str(self.course.id)])
        response = self.client.post(
            choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['unsupported'])

        assert 400 == response.status_code
Ejemplo n.º 4
0
 def setUp(self):
     super(AnonymousLookupTable, self).setUp()
     self.course = CourseFactory.create()
     self.user = UserFactory.create()
     CourseModeFactory.create(
         course_id=self.course.id,
         mode_slug='honor',
         mode_display_name='Honor Code',
     )
     patcher = patch('common.djangoapps.student.models.tracker')
     patcher.start()
     self.addCleanup(patcher.stop)
Ejemplo n.º 5
0
 def test_audit_only_disables_cert(self):
     """
     Tests audit course mode is skipped when rendering certificates page.
     """
     CourseModeFactory.create(course_id=self.course.id, mode_slug='audit')
     response = self.client.get_html(
         self._url(),
     )
     self.assertEqual(response.status_code, 200)
     self.assertContains(response, 'This course does not use a mode that offers certificates.')
     self.assertNotContains(response, 'This module is not enabled.')
     self.assertNotContains(response, 'Loading')
Ejemplo n.º 6
0
 def test_audit_course_mode_is_skipped(self):
     """
     Tests audit course mode is skipped when rendering certificates page.
     """
     CourseModeFactory.create(course_id=self.course.id)
     CourseModeFactory.create(course_id=self.course.id, mode_slug='verified')
     response = self.client.get_html(
         self._url(),
     )
     self.assertEqual(response.status_code, 200)
     self.assertContains(response, 'verified')
     self.assertNotContains(response, 'audit')
Ejemplo n.º 7
0
    def test_create_content_gating_partition_happy_path(self):

        mock_course = Mock(id=self.course_key, user_partitions={})
        CourseModeFactory.create(course_id=mock_course.id, mode_slug='audit')
        CourseModeFactory.create(course_id=mock_course.id, mode_slug='verified')
        ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))

        with patch(
            'openedx.features.content_type_gating.partitions.ContentTypeGatingPartitionScheme.create_user_partition'
        ) as mock_create:
            partition = create_content_gating_partition(mock_course)
            assert partition == mock_create.return_value
Ejemplo n.º 8
0
    def setUp(self):
        super(TestConditionalContentAccess, self).setUp()

        # Add a verified mode to the course
        CourseModeFactory.create(course_id=self.course.id, mode_slug='audit')
        CourseModeFactory.create(course_id=self.course.id,
                                 mode_slug='verified')

        # Create variables that more accurately describe the student's function
        self.student_audit_a = self.student_a
        self.student_audit_b = self.student_b

        # Create verified students
        self.student_verified_a = UserFactory.create(
            username='******',
            email='*****@*****.**')
        CourseEnrollmentFactory.create(user=self.student_verified_a,
                                       course_id=self.course.id,
                                       mode='verified')
        self.student_verified_b = UserFactory.create(
            username='******',
            email='*****@*****.**')
        CourseEnrollmentFactory.create(user=self.student_verified_b,
                                       course_id=self.course.id,
                                       mode='verified')

        # Put students into content gating groups
        UserCourseTagFactory(
            user=self.student_verified_a,
            course_id=self.course.id,
            key='xblock.partition_service.partition_{0}'.format(
                self.partition.id),
            value=str('0'),
        )
        UserCourseTagFactory(
            user=self.student_verified_b,
            course_id=self.course.id,
            key='xblock.partition_service.partition_{0}'.format(
                self.partition.id),
            value=str('1'),
        )
        # Create blocks to go into the verticals
        self.block_a = ItemFactory.create(
            category='problem',
            parent=self.vertical_a,
            metadata=METADATA,
        )
        self.block_b = ItemFactory.create(
            category='problem',
            parent=self.vertical_b,
            metadata=METADATA,
        )
Ejemplo n.º 9
0
    def test_hide_nav(self):
        # Create the course modes
        for mode in ["honor", "verified"]:
            CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)

        # Load the track selection page
        url = reverse('course_modes_choose', args=[str(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")
Ejemplo n.º 10
0
 def test_is_mode_upsellable(self, mode, is_upsellable):
     """
     Test if this is a mode that is upsellable
     """
     CourseModeFactory.create(mode_slug=mode, course_id=self.course.id)
     if mode == CourseMode.CREDIT_MODE:
         CourseModeFactory.create(mode_slug=CourseMode.VERIFIED,
                                  course_id=self.course.id)
     enrollment = CourseEnrollmentFactory(is_active=True,
                                          mode=mode,
                                          course_id=self.course.id,
                                          user=self.user)
     assert is_mode_upsellable(self.user, enrollment) is is_upsellable
Ejemplo n.º 11
0
 def setUp(self):
     super().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()
Ejemplo n.º 12
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)

        # 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=[str(self.course.id)])
        response = self.client.get(url)

        if show_upsell:
            self.assertContains(response, "Credit")
        else:
            self.assertNotContains(response, "Credit")
Ejemplo n.º 13
0
    def setUp(self):
        super().setUp()

        # Create a course and course modes
        self.course = CourseFactory.create()
        CourseModeFactory.create(mode_slug='honor', course_id=self.course.id)
        CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=10)

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

        # Construct the URL for the track selection page
        self.url = reverse('course_modes_choose', args=[str(self.course.id)])
Ejemplo n.º 14
0
 def setUpClass(cls):
     super().setUpClass()
     cls.store = modulestore()
     cls.user = UserFactory()
     cls.program = ProgramFactory(type=MICROBACHELORS)
     cls.catalog_course_run = cls.program['courses'][0]['course_runs'][0]
     cls.course_key = CourseKey.from_string(cls.catalog_course_run['key'])
     cls.course_run = CourseFactory.create(
         org=cls.course_key.org,
         number=cls.course_key.course,
         run=cls.course_key.run,
         modulestore=cls.store,
     )
     CourseModeFactory.create(course_id=cls.course_run.id, mode_slug=CourseMode.VERIFIED)
Ejemplo n.º 15
0
 def test_enrollment_track_partitions_and_content_groups(self):
     """
     Test what is displayed with both enrollment groups and content groups.
     """
     CourseModeFactory.create(course_id=self.course.id, mode_slug='audit')
     CourseModeFactory.create(course_id=self.course.id,
                              mode_slug='verified')
     self.create_content_groups(self.pet_groups)
     self.verify_visibility_view_contains(self.video_location, [
         self.CONTENT_GROUPS_TITLE, 'Cat Lovers', 'Dog Lovers',
         self.ENROLLMENT_GROUPS_TITLE, 'audit course', 'verified course'
     ])
     self.verify_visibility_view_does_not_contain(
         self.video_location, [self.NO_CONTENT_OR_ENROLLMENT_GROUPS])
Ejemplo n.º 16
0
    def setUp(self):
        super(TrackSelectionEmbargoTest, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments

        # Create a course and course modes
        self.course = CourseFactory.create()
        CourseModeFactory.create(mode_slug='honor', course_id=self.course.id)
        CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=10)

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

        # Construct the URL for the track selection page
        self.url = reverse('course_modes_choose', args=[six.text_type(self.course.id)])
Ejemplo n.º 17
0
    def assertProfessionalModeBypassed(self):
        """ Verifies that the view returns HTTP 406 when a course with no honor or audit mode is encountered. """

        CourseMode.objects.filter(course_id=self.course.id).delete()
        mode = CourseMode.NO_ID_PROFESSIONAL_MODE
        sku_string = str(uuid4().hex)
        CourseModeFactory.create(course_id=self.course.id, mode_slug=mode, mode_display_name=mode,
                                 sku=sku_string, bulk_sku=f'BULK-{sku_string}')
        response = self._post_to_view()

        # The view should return an error status code
        assert response.status_code == 406
        msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=self.course.id)
        self.assertResponseMessage(response, msg)
Ejemplo n.º 18
0
 def setUp(self):
     super().setUp()
     self.service = EnrollmentsService()
     self.course = CourseFactory.create()
     self.course_modes = [
         CourseMode.HONOR, CourseMode.VERIFIED, CourseMode.AUDIT
     ]
     for x in range(3):
         CourseModeFactory.create(mode_slug=self.course_modes[x],
                                  course_id=self.course.id)
         user = UserFactory(username='******'.format(x))
         CourseEnrollment.enroll(user,
                                 self.course.id,
                                 mode=self.course_modes[x])
    def test_with_two_verifications(self):
        # checking if a user has two verification and but most recent verification course deadline is expired

        self._setup_mode_and_enrollment(self.DATES[self.FUTURE], "verified")

        # The student has an approved verification
        attempt = SoftwareSecurePhotoVerification.objects.create(
            user=self.user)
        attempt.mark_ready()
        attempt.submit()
        attempt.approve()
        # Making created at to previous date to differentiate with 2nd attempt.
        attempt.created_at = datetime.now(UTC) - timedelta(days=1)
        attempt.save()

        # Expect that the successfully verified message is shown
        self._assert_course_verification_status(VERIFY_STATUS_APPROVED)

        # Check that the "verification good until" date is displayed
        response = self.client.get(self.dashboard_url)
        self.assertContains(response,
                            attempt.expiration_datetime.strftime("%m/%d/%Y"))

        # Adding another verification with different course.
        # Its created_at is greater than course deadline.
        course2 = CourseFactory.create()
        CourseModeFactory.create(course_id=course2.id,
                                 mode_slug="verified",
                                 expiration_datetime=self.DATES[self.PAST])
        CourseEnrollmentFactory(course_id=course2.id,
                                user=self.user,
                                mode="verified")

        # The student has an approved verification
        attempt2 = SoftwareSecurePhotoVerification.objects.create(
            user=self.user)
        attempt2.mark_ready()
        attempt2.submit()
        attempt2.approve()
        attempt2.save()

        # Mark the attemp2 as approved so its date will appear on dasboard.
        self._assert_course_verification_status(VERIFY_STATUS_APPROVED)
        response2 = self.client.get(self.dashboard_url)
        self.assertContains(response2,
                            attempt2.expiration_datetime.strftime("%m/%d/%Y"))
        self.assertContains(response2,
                            attempt2.expiration_datetime.strftime("%m/%d/%Y"),
                            count=2)
Ejemplo n.º 20
0
def _create_course_run(self_paced=True, start_day_offset=-1):
    """ Create a new course run and course modes.

    Both audit and verified `CourseMode` objects will be created for the course run.
    """
    now = datetime.datetime.now(utc)
    start = now + datetime.timedelta(days=start_day_offset)
    course = CourseFactory.create(start=start, self_paced=self_paced)

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

    return course
Ejemplo n.º 21
0
    def setUp(self):
        super().setUp()
        self.service = EnrollmentsService()
        self.course = CourseOverviewFactory.create(enable_proctored_exams=True)
        self.course_modes = [
            CourseMode.AUDIT,
            CourseMode.EXECUTIVE_EDUCATION,
            CourseMode.HONOR,
            CourseMode.MASTERS,
            CourseMode.PROFESSIONAL,
            CourseMode.VERIFIED,
        ]

        for index in range(len(self.course_modes)):
            CourseModeFactory.create(mode_slug=self.course_modes[index], course_id=self.course.id)
Ejemplo n.º 22
0
    def test_certificate_header_data(self):
        """
        Test that get_certificate_header_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 = get_certificate_header_context(is_secure=True)

        # Make sure there are not unexpected keys in dict returned by 'get_certificate_header_context'
        self.assertCountEqual(list(data.keys()), ['logo_src', 'logo_url'])
        assert self.configuration['logo_image_url'] in data['logo_src']

        assert self.configuration['SITE_NAME'] in data['logo_url']
    def _setup_mode_and_enrollment(self, deadline, enrollment_mode):
        """Create a course mode and enrollment.

        Arguments:
            deadline (datetime): The deadline for submitting your verification.
            enrollment_mode (str): The mode of the enrollment.

        """
        CourseModeFactory.create(course_id=self.course.id,
                                 mode_slug="verified",
                                 expiration_datetime=deadline)
        CourseEnrollmentFactory(course_id=self.course.id,
                                user=self.user,
                                mode=enrollment_mode)
        VerificationDeadline.set_deadline(self.course.id, deadline)
Ejemplo n.º 24
0
    def setUp(self):
        super().setUp()
        self.url = reverse('commerce_api:v0:baskets:create')
        self._login()

        self.course = CourseFactory.create()

        # TODO Verify this is the best method to create CourseMode objects.
        # TODO Find/create constants for the modes.
        for mode in [CourseMode.HONOR, CourseMode.VERIFIED, CourseMode.AUDIT]:
            sku_string = str(uuid4().hex)
            CourseModeFactory.create(course_id=self.course.id,
                                     mode_slug=mode,
                                     mode_display_name=mode,
                                     sku=sku_string,
                                     bulk_sku=f'BULK-{sku_string}')
Ejemplo n.º 25
0
 def test_enrollment_track_partitions_only(self):
     """
     Test what is displayed with no content groups but 2 enrollment modes registered.
     In all the cases where no enrollment modes are explicitly added, only the default
     enrollment mode exists, and we do not show it as an option (unless the course staff
     member has previously selected it).
     """
     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.verify_visibility_view_does_not_contain(
         self.video_location,
         [self.NO_CONTENT_OR_ENROLLMENT_GROUPS, self.CONTENT_GROUPS_TITLE])
    def test_already_upgraded(self):
        course = CourseFactory.create(
            start=now() - timedelta(days=30),
            run='test',
            display_name='test',
        )
        course_mode = CourseModeFactory.create(mode_slug=CourseMode.VERIFIED,
                                               course_id=course.id,
                                               min_price=10,
                                               sku=str(uuid4().hex))
        CourseEnrollmentFactory.create(is_active=True,
                                       mode=course_mode,
                                       course_id=course.id,
                                       user=self.user)

        response = self.client.get(self.url, {'course_id': str(course.id)})
        assert response.status_code == 200
        result = response.data
        assert 'basket_url' in result
        assert bool(result['basket_url'])
        expected = {
            'show_upsell': False,
            'upsell_flag': True,
            'experiment_bucket': 1,
            'user_upsell': False,
            'basket_url': result['basket_url'],
            # Example basket_url: u'/verify_student/upgrade/org.0/course_0/test/'
        }
        assert result == expected
Ejemplo n.º 27
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=[str(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
        assert 'donation_for_course' in self.client.session
        assert str(self.course.id) in self.client.session['donation_for_course']

        actual_amount = self.client.session['donation_for_course'][str(self.course.id)]
        expected_amount = decimal.Decimal(self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution'])
        assert actual_amount == expected_amount
Ejemplo n.º 28
0
    def test_enrollments_not_deleted(self):
        """ Recreating a CourseOverview with an outdated version should not delete the associated enrollment. """
        course = CourseFactory(self_paced=True)
        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=30),
        )

        # Create a CourseOverview with an outdated version
        course_overview = CourseOverview.load_from_module_store(course.id)
        course_overview.version = CourseOverview.VERSION - 1
        course_overview.save()

        # Create an inactive enrollment with this course overview
        enrollment = CourseEnrollmentFactory(
            user=self.user,
            course_id=course.id,
            mode=CourseMode.AUDIT,
            course=course_overview,
        )

        # Re-fetch the CourseOverview record.
        # As a side effect, this will recreate the record, and update the version.
        course_overview_new = CourseOverview.get_from_id(course.id)
        assert course_overview_new.version == CourseOverview.VERSION

        # Ensure that the enrollment record was unchanged during this re-creation
        enrollment_refetched = CourseEnrollment.objects.filter(
            id=enrollment.id)
        assert enrollment_refetched.exists()
        assert enrollment_refetched.all()[0] == enrollment
Ejemplo n.º 29
0
    def test_check_for_existing_entitlement_and_enroll(self,
                                                       mock_get_course_uuid):
        course = CourseFactory()
        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=now() + timedelta(days=1))
        entitlement = CourseEntitlementFactory.create(
            mode=CourseMode.VERIFIED,
            user=self.user,
        )
        mock_get_course_uuid.return_value = entitlement.course_uuid

        assert not CourseEnrollment.is_enrolled(user=self.user,
                                                course_key=course.id)

        CourseEntitlement.check_for_existing_entitlement_and_enroll(
            user=self.user,
            course_run_key=course.id,
        )

        assert CourseEnrollment.is_enrolled(user=self.user,
                                            course_key=course.id)

        entitlement.refresh_from_db()
        assert entitlement.enrollment_course_run
Ejemplo n.º 30
0
    def test_update_course_mode_happy_path(self):
        new_mode = CourseModeFactory.create(
            course_id=self.course_key,
            mode_slug='prof-ed',
            mode_display_name='Professional Education',
            min_price=100,
            currency='jpy',
        )
        self.client.login(username=self.global_staff.username,
                          password=self.user_password)
        url = self.get_url(mode_slug='prof-ed')

        response = self.client.patch(
            url,
            data=json.dumps({
                'min_price': 222,
                'mode_display_name': 'Something Else',
            }),
            content_type='application/merge-patch+json',
        )

        assert status.HTTP_204_NO_CONTENT == response.status_code
        updated_mode = CourseMode.objects.get(course_id=self.course_key,
                                              mode_slug='prof-ed')
        assert 222 == updated_mode.min_price
        assert 'Something Else' == updated_mode.mode_display_name
        assert 'jpy' == updated_mode.currency
        self.addCleanup(lambda mode: mode.delete(), new_mode)