コード例 #1
0
    def test_content_availability_date(self, mock_get_course_run_details):
        """
        Content availability date is course start date or enrollment date, whichever is later.
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        # Content availability date is enrollment date
        start_date = now() - timedelta(weeks=10)
        past_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, past_course.id, CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, past_course)
        self.assertEqual(result, None)

        add_course_mode(past_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(self.user, past_course)
        content_availability_date = enrollment.created
        self.assertEqual(result, content_availability_date + access_duration)

        # Content availability date is course start date
        start_date = now() + timedelta(weeks=10)
        future_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, future_course.id, CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, future_course)
        self.assertEqual(result, None)

        add_course_mode(future_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(self.user, future_course)
        content_availability_date = start_date
        self.assertEqual(result, content_availability_date + access_duration)
コード例 #2
0
    def test_content_availability_date(self, mock_get_course_run_details):
        """
        Content availability date is course start date or enrollment date, whichever is later.
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        # Content availability date is enrollment date
        start_date = now() - timedelta(weeks=10)
        past_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, past_course.id,
                                             CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, past_course)
        self.assertEqual(result, None)

        add_course_mode(past_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(self.user, past_course)
        content_availability_date = enrollment.created
        self.assertEqual(result, content_availability_date + access_duration)

        # Content availability date is course start date
        start_date = now() + timedelta(weeks=10)
        future_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, future_course.id,
                                             CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, future_course)
        self.assertEqual(result, None)

        add_course_mode(future_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(self.user, future_course)
        content_availability_date = start_date
        self.assertEqual(result, content_availability_date + access_duration)
コード例 #3
0
    def test_content_availability_date(self, mock_get_course_run_details):
        """
        Content availability date is course start date or enrollment date, whichever is later.
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        # Content availability date is enrollment date
        start_date = now() - timedelta(weeks=10)
        past_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, past_course.id,
                                             CourseMode.AUDIT)
        CourseDurationLimitConfig.objects.create(
            enabled=True,
            course=CourseOverview.get_from_id(past_course.id),
            enabled_as_of=past_course.start,
        )
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(past_course.id),
        )
        assert result is None

        add_course_mode(past_course, mode_slug=CourseMode.AUDIT)
        add_course_mode(past_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(past_course.id),
        )
        content_availability_date = enrollment.created
        assert result == (content_availability_date + access_duration)

        # Content availability date is course start date
        start_date = now() + timedelta(weeks=10)
        future_course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, future_course.id,
                                             CourseMode.AUDIT)
        CourseDurationLimitConfig.objects.create(
            enabled=True,
            course=CourseOverview.get_from_id(future_course.id),
            enabled_as_of=past_course.start,
        )
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(future_course.id),
        )
        assert result is None

        add_course_mode(future_course, mode_slug=CourseMode.AUDIT)
        add_course_mode(future_course, upgrade_deadline_expired=False)
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(future_course.id),
        ).replace(microsecond=0)
        content_availability_date = start_date.replace(microsecond=0)
        assert result == (content_availability_date + access_duration)
コード例 #4
0
    def test_get_access_expiration_data(self):
        enrollment = CourseEnrollmentFactory()
        overview = enrollment.course
        user = enrollment.user

        now = timezone.now()
        upgrade_deadline = now + timedelta(days=2)
        CourseModeFactory(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.VERIFIED,
            expiration_datetime=upgrade_deadline,
        )
        CourseModeFactory(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.AUDIT,
        )

        expiration_date = get_user_course_expiration_date(user, overview)
        assert expiration_date is not None

        data = get_access_expiration_data(user, overview)
        assert data == \
               {
                   'expiration_date': expiration_date,
                   'masquerading_expired_course': False,
                   'upgrade_deadline': upgrade_deadline,
                   'upgrade_url': '/dashboard'
               }
コード例 #5
0
    def test_all_courses_with_weeks_to_complete(
        self,
        weeks_to_complete,
        access_duration,
        self_paced,
        mock_get_course_run_details,
    ):
        """
        Test that access_duration for a course is equal to the value of the weeks_to_complete field in discovery.
        If weeks_to_complete is None, access_duration will be the MIN_DURATION constant.

        """
        if self_paced:
            self.course.self_paced = True
        mock_get_course_run_details.return_value = {
            'weeks_to_complete': weeks_to_complete
        }
        enrollment = CourseEnrollment.enroll(self.user, self.course.id,
                                             CourseMode.AUDIT)
        CourseDurationLimitConfig.objects.create(
            enabled=True,
            course=CourseOverview.get_from_id(self.course.id),
            enabled_as_of=self.course.start,
        )
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(self.course.id),
        )
        assert result == (enrollment.created + access_duration)
コード例 #6
0
ファイル: test_access.py プロジェクト: uetuluk/edx-platform
    def test_schedule_start_date_in_past(self):
        """
        Test that when schedule start date is before course start or
        enrollment date, content_availability_date is set to max of course start
        or enrollment date
        """
        enrollment = CourseEnrollmentFactory.create(course=self.course)
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.VERIFIED,
        )
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.AUDIT,
        )
        Schedule.objects.update(start_date=datetime(2017, 1, 1, tzinfo=UTC))

        content_availability_date = max(enrollment.created,
                                        enrollment.course.start)
        access_duration = get_user_course_duration(enrollment.user,
                                                   enrollment.course)
        expected_course_expiration_date = content_availability_date + access_duration

        duration_limit_upgrade_deadline = get_user_course_expiration_date(
            enrollment.user, enrollment.course)
        assert duration_limit_upgrade_deadline is not None
        assert duration_limit_upgrade_deadline == expected_course_expiration_date
コード例 #7
0
    def test_schedule_start_date_in_past(self):
        """
        Test that when schedule start date is before course start or
        enrollment date, content_availability_date is set to max of course start
        or enrollment date
        """
        enrollment = CourseEnrollmentFactory.create(
            course__start=datetime(2018, 1, 1, tzinfo=UTC),
            course__self_paced=True,
        )
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.VERIFIED,
        )
        CourseModeFactory.create(
            course_id=enrollment.course.id,
            mode_slug=CourseMode.AUDIT,
        )
        ScheduleFactory.create(
            enrollment=enrollment,
            start_date=datetime(2017, 1, 1, tzinfo=UTC),
        )

        content_availability_date = max(enrollment.created,
                                        enrollment.course.start)
        access_duration = get_user_course_duration(enrollment.user,
                                                   enrollment.course)
        expected_course_expiration_date = content_availability_date + access_duration

        duration_limit_upgrade_deadline = get_user_course_expiration_date(
            enrollment.user, enrollment.course)
        self.assertIsNotNone(duration_limit_upgrade_deadline)
        self.assertEqual(duration_limit_upgrade_deadline,
                         expected_course_expiration_date)
コード例 #8
0
 def test_instructor_paced_no_end_date(self):
     """Tests that instructor paced with no end dates returns default (minimum)"""
     self.course.self_paced = False
     enrollment = CourseEnrollment.enroll(self.user, self.course.id,
                                          CourseMode.AUDIT)
     result = get_user_course_expiration_date(self.user, self.course)
     self.assertEqual(result, enrollment.created + MIN_DURATION)
コード例 #9
0
ファイル: test_access.py プロジェクト: saltfun/edx-platform
    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__start=datetime(2018, 1, 1, tzinfo=UTC),
            course__self_paced=True,
        )
        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,
        )
        ScheduleFactory.create(
            enrollment=enrollment,
            upgrade_deadline=schedule_upgrade_deadline,
        )

        duration_limit_upgrade_deadline = get_user_course_expiration_date(
            enrollment.user, enrollment.course)
        self.assertIsNotNone(duration_limit_upgrade_deadline)

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

        self.assertDateInMessage(duration_limit_upgrade_deadline, message)
        self.assertIn('data-timezone="Asia/Tokyo"', 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:
            self.assertNotIn("Upgrade by", message)
コード例 #10
0
ファイル: serializers.py プロジェクト: jolyonb/edx-platform
    def get_audit_access_expires(self, model):
        """
        Returns expiration date for a course audit expiration, if any or null
        """
        if not CourseDurationLimitConfig.enabled_for_enrollment(user=model.user, course_key=model.course.id):
            return None

        return get_user_course_expiration_date(model.user, model.course)
コード例 #11
0
def get_audit_access_expiration(user, course):
    """
    Return the expiration date for the user's audit access to this course.
    """
    if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id):
        return None

    return get_user_course_expiration_date(user, course)
コード例 #12
0
    def get_audit_access_expires(self, model):
        """
        Returns expiration date for a course audit expiration, if any or null
        """
        if not CourseDurationLimitConfig.enabled_for_enrollment(model.user, model.course):
            return None

        return get_user_course_expiration_date(model.user, model.course)
コード例 #13
0
 def test_instructor_paced(self):
     """Tests that instructor paced courses give the learner start_date - end_date time in the course"""
     expected_difference = timedelta(weeks=6)
     self.course.self_paced = False
     self.course.end = self.course.start + expected_difference
     enrollment = CourseEnrollment.enroll(self.user, self.course.id,
                                          CourseMode.AUDIT)
     result = get_user_course_expiration_date(self.user, self.course)
     self.assertEqual(result, enrollment.created + expected_difference)
コード例 #14
0
ファイル: utils.py プロジェクト: edx/edx-platform
def get_audit_access_expiration(user, course):
    """
    Return the expiration date for the user's audit access to this course.
    """
    if AUDIT_DEADLINE_FLAG.is_enabled():
        if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id):
            return None

        return get_user_course_expiration_date(user, course)
    return None
コード例 #15
0
    def test_generate_course_expired_message(self, offsets):
        now = timezone.now()
        schedule_offset, course_offset = offsets

        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

        def format_date(date):
            return strftime_localized(date, u'%b %-d, %Y')

        enrollment = CourseEnrollmentFactory.create(
            course__start=datetime(2018, 1, 1, tzinfo=UTC),
            course__self_paced=True,
        )
        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,
        )
        ScheduleFactory.create(
            enrollment=enrollment,
            upgrade_deadline=schedule_upgrade_deadline,
        )

        duration_limit_upgrade_deadline = get_user_course_expiration_date(
            enrollment.user, enrollment.course)
        self.assertIsNotNone(duration_limit_upgrade_deadline)

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

        self.assertIn(format_date(duration_limit_upgrade_deadline), 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.assertIn(format_date(schedule_upgrade_deadline), message)
        elif upgradeable and has_upgrade_deadline:
            self.assertIn(format_date(course_upgrade_deadline), message)
        else:
            self.assertNotIn("Upgrade by", message)
コード例 #16
0
ファイル: test_access.py プロジェクト: edx/edx-platform
    def test_generate_course_expired_message(self, offsets):
        now = timezone.now()
        schedule_offset, course_offset = offsets

        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

        def format_date(date):
            return strftime_localized(date, u'%b %-d, %Y')

        enrollment = CourseEnrollmentFactory.create(
            course__start=datetime(2018, 1, 1, tzinfo=UTC),
            course__self_paced=True,
        )
        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,
        )
        ScheduleFactory.create(
            enrollment=enrollment,
            upgrade_deadline=schedule_upgrade_deadline,
        )

        duration_limit_upgrade_deadline = get_user_course_expiration_date(enrollment.user, enrollment.course)
        self.assertIsNotNone(duration_limit_upgrade_deadline)

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

        self.assertIn(format_date(duration_limit_upgrade_deadline), 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.assertIn(format_date(schedule_upgrade_deadline), message)
        elif upgradeable and has_upgrade_deadline:
            self.assertIn(format_date(course_upgrade_deadline), message)
        else:
            self.assertNotIn("Upgrade by", message)
コード例 #17
0
    def handle_goal(goal, today, sunday_date, monday_date):
        """Sends an email reminder for a single CourseGoal, if it passes all our checks"""
        if not COURSE_GOALS_NUMBER_OF_DAYS_GOALS.is_enabled(goal.course_key):
            return False

        enrollment = CourseEnrollment.get_enrollment(goal.user,
                                                     goal.course_key,
                                                     select_related=['course'])
        # If you're not actively enrolled in the course or your enrollment was this week
        if not enrollment or not enrollment.is_active or enrollment.created.date(
        ) >= monday_date:
            return False

        audit_access_expiration_date = get_user_course_expiration_date(
            goal.user, enrollment.course_overview)
        # If an audit user's access expires this week, exclude them from the email since they may not
        # be able to hit their goal anyway
        if audit_access_expiration_date and audit_access_expiration_date.date(
        ) <= sunday_date:
            return False

        cert = get_certificate_for_user_id(goal.user, goal.course_key)
        # If a user has a downloadable certificate, we will consider them as having completed
        # the course and opt them out of receiving emails
        if cert and cert.status == CertificateStatuses.downloadable:
            return False

        # Check the number of days left to successfully hit their goal
        week_activity_count = UserActivity.objects.filter(
            user=goal.user,
            course_key=goal.course_key,
            date__gte=monday_date,
        ).count()
        required_days_left = goal.days_per_week - week_activity_count
        # The weekdays are 0 indexed, but we want this to be 1 to match required_days_left.
        # Essentially, if today is Sunday, days_left_in_week should be 1 since they have Sunday to hit their goal.
        days_left_in_week = SUNDAY_WEEKDAY - today.weekday() + 1

        # We want to email users in the morning of their timezone
        user_timezone = get_user_timezone_or_last_seen_timezone_or_utc(
            goal.user)
        now_in_users_timezone = datetime.now(user_timezone)
        if not 9 <= now_in_users_timezone.hour < 12:
            return False

        if required_days_left == days_left_in_week:
            send_ace_message(goal)
            CourseGoalReminderStatus.objects.update_or_create(
                goal=goal, defaults={'email_reminder_sent': True})
            return True

        return False
コード例 #18
0
def get_base_experiment_metadata_context(course, user, enrollment,
                                         user_enrollments):
    """
    Return a context dictionary with the keys used by dashboard_metadata.html and user_metadata.html
    """
    enrollment_mode = None
    enrollment_time = None
    # TODO: clean up as part of REVEM-199 (START)
    program_key = get_program_context(course, user_enrollments)
    # TODO: clean up as part of REVEM-199 (END)
    schedule_start = None
    if enrollment and enrollment.is_active:
        enrollment_mode = enrollment.mode
        enrollment_time = enrollment.created

        try:
            schedule_start = enrollment.schedule.start_date
        except Schedule.DoesNotExist:
            pass

    # upgrade_link, dynamic_upgrade_deadline and course_upgrade_deadline should be None
    # if user has passed their dynamic pacing deadline.
    upgrade_link, dynamic_upgrade_deadline, course_upgrade_deadline = check_and_get_upgrade_link_and_date(
        user, enrollment, course)

    duration = get_user_course_duration(user, course)
    deadline = duration and get_user_course_expiration_date(user, course)

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price':
        six.text_type(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'schedule_start': schedule_start,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'dynamic_upgrade_deadline': dynamic_upgrade_deadline,
        'course_upgrade_deadline': course_upgrade_deadline,
        'audit_access_deadline': deadline,
        'course_duration': duration,
        'course_key': course.id,
        'course_display_name': course.display_name_with_default,
        'course_start': course.start,
        'course_end': course.end,
        # TODO: clean up as part of REVEM-199 (START)
        'program_key_fields': program_key,
        # TODO: clean up as part of REVEM-199 (END)
    }
コード例 #19
0
    def test_expired_upgrade_deadline(self, mock_get_course_run_details):
        """
        The expiration date still exists if the upgrade deadline has passed
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        start_date = now() - timedelta(weeks=10)
        course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, course.id,
                                             CourseMode.AUDIT)
        add_course_mode(course, upgrade_deadline_expired=True)
        result = get_user_course_expiration_date(self.user, course)
        content_availability_date = enrollment.created
        self.assertEqual(result, content_availability_date + access_duration)
コード例 #20
0
    def test_expired_upgrade_deadline(self, mock_get_course_run_details):
        """
        The expiration date still exists if the upgrade deadline has passed
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        start_date = now() - timedelta(weeks=10)
        course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, course.id, CourseMode.AUDIT)
        add_course_mode(course, upgrade_deadline_expired=True)
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(course.id),
        )
        content_availability_date = enrollment.created
        self.assertEqual(result, content_availability_date + access_duration)
コード例 #21
0
ファイル: utils.py プロジェクト: cmltaWt0/edx-platform
def serialize_upgrade_info(user, course_overview, enrollment):
    """
    Return verified mode upgrade information, or None.

    This is used in a few API views to provide consistent upgrade info to frontends.
    """
    if not can_show_verified_upgrade(user, enrollment):
        return None

    mode = CourseMode.verified_mode_for_course(course=course_overview)
    return {
        'access_expiration_date': get_user_course_expiration_date(user, course_overview),
        'currency': mode.currency.upper(),
        'currency_symbol': get_currency_symbol(mode.currency.upper()),
        'price': mode.min_price,
        'sku': mode.sku,
        'upgrade_url': verified_upgrade_deadline_link(user, course_overview),
    }
コード例 #22
0
    def test_all_courses_with_weeks_to_complete(
        self,
        weeks_to_complete,
        access_duration,
        self_paced,
        mock_get_course_run_details,
    ):
        """
        Test that access_duration for a course is equal to the value of the weeks_to_complete field in discovery.
        If weeks_to_complete is None, access_duration will be the MIN_DURATION constant.

        """
        if self_paced:
            self.course.self_paced = True
        mock_get_course_run_details.return_value = {'weeks_to_complete': weeks_to_complete}
        enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, self.course)
        self.assertEqual(result, enrollment.created + access_duration)
コード例 #23
0
    def test_all_courses_with_weeks_to_complete(
        self,
        weeks_to_complete,
        access_duration,
        self_paced,
        mock_get_course_run_details,
    ):
        """
        Test that access_duration for a course is equal to the value of the weeks_to_complete field in discovery.
        If weeks_to_complete is None, access_duration will be the MIN_DURATION constant.

        """
        if self_paced:
            self.course.self_paced = True
        mock_get_course_run_details.return_value = {'weeks_to_complete': weeks_to_complete}
        enrollment = CourseEnrollment.enroll(self.user, self.course.id, CourseMode.AUDIT)
        result = get_user_course_expiration_date(self.user, self.course)
        self.assertEqual(result, enrollment.created + access_duration)
コード例 #24
0
 def test_self_paced_with_weeks_to_complete(
     self,
     weeks_to_complete,
     expected_difference,
     mock_get_course_run_details,
 ):
     """
         Tests that self paced courses allow for a (bounded) # of weeks in courses determined via
         weeks_to_complete field in discovery. If the field doesn't exist, it should return default (minimum)
     """
     self.course.self_paced = True
     mock_get_course_run_details.return_value = {
         'weeks_to_complete': weeks_to_complete
     }
     enrollment = CourseEnrollment.enroll(self.user, self.course.id,
                                          CourseMode.AUDIT)
     result = get_user_course_expiration_date(self.user, self.course)
     self.assertEqual(result, enrollment.created + expected_difference)
コード例 #25
0
    def test_expired_upgrade_deadline(self, mock_get_course_run_details):
        """
        The expiration date still exists if the upgrade deadline has passed
        """
        access_duration = timedelta(weeks=7)
        mock_get_course_run_details.return_value = {'weeks_to_complete': 7}

        start_date = now() - timedelta(weeks=10)
        course = CourseFactory(start=start_date)
        enrollment = CourseEnrollment.enroll(self.user, course.id, CourseMode.AUDIT)
        CourseDurationLimitConfig.objects.create(
            enabled=True,
            course=CourseOverview.get_from_id(course.id),
            enabled_as_of=course.start,
        )
        add_course_mode(course, mode_slug=CourseMode.AUDIT)
        add_course_mode(course, upgrade_deadline_expired=True)
        result = get_user_course_expiration_date(
            self.user,
            CourseOverview.get_from_id(course.id),
        )
        content_availability_date = enrollment.created
        assert result == (content_availability_date + access_duration)
コード例 #26
0
ファイル: views.py プロジェクト: ririfat750/edx-platform
    def verified_mode(self):
        """
        Return verified mode information, or None.
        """
        if not can_show_verified_upgrade(self.effective_user,
                                         self.enrollment_object):
            return None

        mode = CourseMode.verified_mode_for_course(self.course_key)
        return {
            'access_expiration_date':
            get_user_course_expiration_date(self.effective_user,
                                            self.overview),
            'price':
            mode.min_price,
            'currency':
            mode.currency.upper(),
            'currency_symbol':
            get_currency_symbol(mode.currency.upper()),
            'sku':
            mode.sku,
            'upgrade_url':
            verified_upgrade_deadline_link(self.effective_user, self.overview),
        }
コード例 #27
0
    def test_register_course_expired_message(self, language, offsets,
                                             mock_messages):
        now = timezone.now()
        schedule_offset, course_offset = offsets

        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

        def format_date(date):
            if language.startswith('es-'):
                return strftime_localized(date, '%-d de %b. de %Y').lower()
            else:
                return strftime_localized(date, '%b. %-d, %Y')

        patch_lang = patch(
            'openedx.features.course_duration_limits.access.get_language',
            return_value=language)
        with patch_lang:
            enrollment = CourseEnrollmentFactory.create(
                course__start=datetime(2018, 1, 1, tzinfo=UTC),
                course__self_paced=True,
            )
            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,
            )
            ScheduleFactory.create(
                enrollment=enrollment,
                upgrade_deadline=schedule_upgrade_deadline,
            )
            request = RequestFactory().get('/courseware')
            request.user = enrollment.user

            duration_limit_upgrade_deadline = get_user_course_expiration_date(
                enrollment.user, enrollment.course)
            self.assertIsNotNone(duration_limit_upgrade_deadline)

            register_course_expired_message(request, enrollment.course)
            self.assertEqual(mock_messages.register_info_message.call_count, 1)

            message = str(mock_messages.register_info_message.call_args[0][1])

            self.assertIn(format_date(duration_limit_upgrade_deadline),
                          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.assertIn(format_date(schedule_upgrade_deadline), message)
            elif upgradeable and has_upgrade_deadline:
                self.assertIn(format_date(course_upgrade_deadline), message)
            else:
                self.assertNotIn("Upgrade by", message)
コード例 #28
0
 def date(self):
     return get_user_course_expiration_date(self.user, self.course)
コード例 #29
0
 def test_enrollment_mode(self):
     """Tests that verified enrollments do not have an expiration"""
     CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
     result = get_user_course_expiration_date(self.user, CourseOverview.get_from_id(self.course.id))
     self.assertEqual(result, None)
コード例 #30
0
 def get_audit_access_expires(self, model):
     """
     Returns expiration date for a course audit expiration, if any or null
     """
     return get_user_course_expiration_date(model.user, model.course)
コード例 #31
0
    def get(self, request, course_id, error=None):  # lint-amnesty, pylint: disable=too-many-statements
        """Displays the course mode choice page.

        Args:
            request (`Request`): The Django Request object.
            course_id (unicode): The slash-separated course key.

        Keyword Args:
            error (unicode): If provided, display this error message
                on the page.

        Returns:
            Response

        """
        course_key = CourseKey.from_string(course_id)

        # Check whether the user has access to this course
        # based on country access rules.
        embargo_redirect = embargo_api.redirect_if_blocked(
            course_key,
            user=request.user,
            ip_address=get_client_ip(request)[0],
            url=request.path)
        if embargo_redirect:
            return redirect(embargo_redirect)

        enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(
            request.user, course_key)

        increment('track-selection.{}.{}'.format(
            enrollment_mode, 'active' if is_active else 'inactive'))
        increment('track-selection.views')

        if enrollment_mode is None:
            LOG.info(
                'Rendering track selection for unenrolled user, referred by %s',
                request.META.get('HTTP_REFERER'))

        modes = CourseMode.modes_for_course_dict(course_key)
        ecommerce_service = EcommerceService()

        # We assume that, if 'professional' is one of the modes, it should be the *only* mode.
        # If there are both modes, default to 'no-id-professional'.
        has_enrolled_professional = (
            CourseMode.is_professional_slug(enrollment_mode) and is_active)
        if CourseMode.has_professional_mode(
                modes) and not has_enrolled_professional:
            purchase_workflow = request.GET.get("purchase_workflow", "single")
            redirect_url = IDVerificationService.get_verify_location(
                course_id=course_key)
            if ecommerce_service.is_enabled(request.user):
                professional_mode = modes.get(
                    CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get(
                        CourseMode.PROFESSIONAL)
                if purchase_workflow == "single" and professional_mode.sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(
                        professional_mode.sku)
                if purchase_workflow == "bulk" and professional_mode.bulk_sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(
                        professional_mode.bulk_sku)
            return redirect(redirect_url)

        course = modulestore().get_course(course_key)

        # If there isn't a verified mode available, then there's nothing
        # to do on this page.  Send the user to the dashboard.
        if not CourseMode.has_verified_mode(modes):
            return self._redirect_to_course_or_dashboard(
                course, course_key, request.user)

        # If a user has already paid, redirect them to the dashboard.
        if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES +
                          [CourseMode.NO_ID_PROFESSIONAL_MODE]):
            return self._redirect_to_course_or_dashboard(
                course, course_key, request.user)

        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(str(course_key), None)

        if CourseEnrollment.is_enrollment_closed(request.user, course):
            locale = to_locale(get_language())
            enrollment_end_date = format_datetime(course.enrollment_end,
                                                  'short',
                                                  locale=locale)
            params = six.moves.urllib.parse.urlencode(
                {'course_closed': enrollment_end_date})
            return redirect('{}?{}'.format(reverse('dashboard'), params))

        # When a credit mode is available, students will be given the option
        # to upgrade from a verified mode to a credit mode at the end of the course.
        # This allows students who have completed photo verification to be eligible
        # for university credit.
        # Since credit isn't one of the selectable options on the track selection page,
        # we need to check *all* available course modes in order to determine whether
        # a credit mode is available.  If so, then we show slightly different messaging
        # for the verified track.
        has_credit_upsell = any(
            CourseMode.is_credit_mode(mode)
            for mode in CourseMode.modes_for_course(course_key,
                                                    only_selectable=False))
        course_id = str(course_key)
        gated_content = ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user, course_key=course_key)
        context = {
            "course_modes_choose_url":
            reverse("course_modes_choose", kwargs={'course_id': course_id}),
            "modes":
            modes,
            "has_credit_upsell":
            has_credit_upsell,
            "course_name":
            course.display_name_with_default,
            "course_org":
            course.display_org_with_default,
            "course_num":
            course.display_number_with_default,
            "chosen_price":
            chosen_price,
            "error":
            error,
            "responsive":
            True,
            "nav_hidden":
            True,
            "content_gating_enabled":
            gated_content,
            "course_duration_limit_enabled":
            CourseDurationLimitConfig.enabled_for_enrollment(
                request.user, course),
        }
        context.update(
            get_experiment_user_metadata_context(
                course,
                request.user,
            ))

        title_content = ''
        if enrollment_mode:
            title_content = _(
                "Congratulations!  You are now enrolled in {course_name}"
            ).format(course_name=course.display_name_with_default)

        context["title_content"] = title_content

        if "verified" in modes:
            verified_mode = modes["verified"]
            context["suggested_prices"] = [
                decimal.Decimal(x.strip())
                for x in verified_mode.suggested_prices.split(",")
                if x.strip()
            ]
            price_before_discount = verified_mode.min_price
            course_price = price_before_discount
            enterprise_customer = enterprise_customer_for_request(request)
            LOG.info(
                '[e-commerce calculate API] Going to hit the API for user [%s] linked to [%s] enterprise',
                request.user.username,
                enterprise_customer.get('name') if isinstance(
                    enterprise_customer, dict) else None  # Test Purpose
            )
            if enterprise_customer and verified_mode.sku:
                course_price = get_course_final_price(request.user,
                                                      verified_mode.sku,
                                                      price_before_discount)

            context["currency"] = verified_mode.currency.upper()
            context["currency_symbol"] = get_currency_symbol(
                verified_mode.currency.upper())
            context["min_price"] = course_price
            context["verified_name"] = verified_mode.name
            context["verified_description"] = verified_mode.description
            # if course_price is equal to price_before_discount then user doesn't entitle to any discount.
            if course_price != price_before_discount:
                context["price_before_discount"] = price_before_discount

            if verified_mode.sku:
                context[
                    "use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(
                        request.user)
                context[
                    "ecommerce_payment_page"] = ecommerce_service.payment_page_url(
                    )
                context["sku"] = verified_mode.sku
                context["bulk_sku"] = verified_mode.bulk_sku

        context['currency_data'] = []
        if waffle.switch_is_active('local_currency'):
            if 'edx-price-l10n' not in request.COOKIES:
                currency_data = get_currency_data()
                try:
                    context['currency_data'] = json.dumps(currency_data)
                except TypeError:
                    pass

        language = get_language()
        context['track_links'] = get_verified_track_links(language)

        duration = get_user_course_duration(request.user, course)
        deadline = duration and get_user_course_expiration_date(
            request.user, course)
        if deadline:
            formatted_audit_access_date = strftime_localized_html(
                deadline, 'SHORT_DATE')
            context['audit_access_deadline'] = formatted_audit_access_date
        fbe_is_on = deadline and gated_content

        # Route to correct Track Selection page.
        # REV-2133 TODO Value Prop: remove waffle flag after testing is completed
        # and happy path version is ready to be rolled out to all users.
        if VALUE_PROP_TRACK_SELECTION_FLAG.is_enabled():
            if not error:  # TODO: Remove by executing REV-2355
                if not enterprise_customer_for_request(
                        request):  # TODO: Remove by executing REV-2342
                    if fbe_is_on:
                        return render_to_response("course_modes/fbe.html",
                                                  context)
                    else:
                        return render_to_response("course_modes/unfbe.html",
                                                  context)

        # If error or enterprise_customer, failover to old choose.html page
        return render_to_response("course_modes/choose.html", context)
コード例 #32
0
 def test_enrollment_mode(self):
     """Tests that verified enrollments do not have an expiration"""
     CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
     result = get_user_course_expiration_date(self.user, CourseOverview.get_from_id(self.course.id))
     self.assertEqual(result, None)
コード例 #33
0
 def date(self):
     if not CourseDurationLimitConfig.enabled_for_enrollment(
             self.user, self.course):
         return
     return get_user_course_expiration_date(self.user, self.course)