def enabled_for_enrollment(cls, user=None, course_key=None): """ Return whether Course Duration Limits are enabled for this enrollment. Course Duration Limits are enabled for an enrollment if they are enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if user is None or course_key is None: raise ValueError('Both user and course_key must be specified if no enrollment is provided') enrollment = CourseEnrollment.get_enrollment(user, course_key, ['fbeenrollmentexclusion']) if user is None and enrollment is not None: user = enrollment.user if user and user.id: course_masquerade = get_course_masquerade(user, course_key) if course_masquerade: if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade): return False elif has_staff_roles(user, course_key): return False is_masquerading = get_course_masquerade(user, course_key) no_masquerade = is_masquerading is None student_masquerade = is_masquerading_as_specific_student(user, course_key) # check if user is in holdback if (no_masquerade or student_masquerade) and is_in_holdback(user, enrollment): return False not_student_masquerade = is_masquerading and not student_masquerade # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today # When masquerading as a user group rather than a specific learner, # course duration limits will be on if they are on for the course. # When masquerading as a specific learner, course duration limits # will be on if they are currently on for the learner. if enrollment is None or not_student_masquerade: # we bypass enabled_for_course here and use enabled_as_of_datetime directly # because the correct_modes_for_fbe for FBE check contained in enabled_for_course # is redundant with checks done upstream of this code target_datetime = timezone.now() else: target_datetime = enrollment.created current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
def has_full_access_role_in_masquerade(user, course_key): """ The roles of the masquerade user are used to determine whether the content gate displays. Returns: True if we are masquerading as a full-access generic user False if we are masquerading as a non-full-access generic user None if we are not masquerading or masquerading as a specific student that should go through normal checks """ # The masquerade module imports from us, so avoid a circular dependency here from lms.djangoapps.courseware.masquerade import ( get_course_masquerade, is_masquerading_as_full_access, is_masquerading_as_non_audit_enrollment, is_masquerading_as_specific_student, is_masquerading_as_staff, ) course_masquerade = get_course_masquerade(user, course_key) if not course_masquerade or is_masquerading_as_specific_student( user, course_key): return None return (is_masquerading_as_staff(user, course_key) or is_masquerading_as_full_access(user, course_key, course_masquerade) or is_masquerading_as_non_audit_enrollment(user, course_key, course_masquerade))
def check_start_date(user, days_early_for_beta, start, course_key, display_error_to_user=True, now=None): """ Verifies whether the given user is allowed access given the start date and the Beta offset for the given course. Arguments: display_error_to_user: If True, display this error to users in the UI. Returns: AccessResponse: Either ACCESS_GRANTED or StartDateError. """ start_dates_disabled = settings.FEATURES['DISABLE_START_DATES'] masquerading_as_student = is_masquerading_as_student(user, course_key) if start_dates_disabled and not masquerading_as_student: return ACCESS_GRANTED else: if start is None or in_preview_mode() or get_course_masquerade( user, course_key): return ACCESS_GRANTED if now is None: now = datetime.now(UTC) effective_start = adjust_start_date(user, days_early_for_beta, start, course_key) if now > effective_start: return ACCESS_GRANTED return StartDateError(start, display_error_to_user=display_error_to_user)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None, user_partition=None): """ Return whether Content Type Gating is enabled for this enrollment. Content Type Gating is enabled for an enrollment if it is enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) if user is None and enrollment is not None: user = enrollment.user course_masquerade = get_course_masquerade(user, course_key) no_masquerade = course_masquerade is None student_masquerade = is_masquerading_as_specific_student(user, course_key) user_variable_represents_correct_user = (no_masquerade or student_masquerade) if course_masquerade: if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade, student_masquerade, user_partition): return False # When a request is not in a masquerade state the user variable represents the correct user. elif user and user.id and has_staff_roles(user, course_key): return False # check if user is in holdback if user_variable_represents_correct_user and is_in_holdback(user): return False # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today # Also, ignore enrollment creation date if the user is masquerading. if enrollment is None or course_masquerade: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Content Type Gating is enabled for this enrollment. Content Type Gating is enabled for an enrollment if it is enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today if enrollment is None: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: # TODO: clean up as part of REV-100 experiment_data_holdback_key = EXPERIMENT_DATA_HOLDBACK_KEY.format(user) is_in_holdback = False no_masquerade = get_course_masquerade(user, course_key) is None student_masquerade = is_masquerading_as_specific_student(user, course_key) if user and (no_masquerade or student_masquerade): try: holdback_value = ExperimentData.objects.get( user=user, experiment_id=EXPERIMENT_ID, key=experiment_data_holdback_key, ).value is_in_holdback = holdback_value == 'True' except ExperimentData.DoesNotExist: pass if is_in_holdback: return False current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
def get_group_for_user(cls, course_key, user, user_partition, **kwargs): # pylint: disable=unused-argument """ Returns the Group for the specified user. """ # First, check if we have to deal with masquerading. # If the current user is masquerading as a specific student, use the # same logic as normal to return that student's group. If the current # user is masquerading as a generic student in a specific group, then # return that group. if get_course_masquerade(user, course_key) and not is_masquerading_as_specific_student(user, course_key): return get_masquerading_user_group(course_key, user, user_partition) # For now, treat everyone as a Full-access user, until we have the rest of the # feature gating logic in place. if not CONTENT_TYPE_GATING_FLAG.is_enabled(): return cls.FULL_ACCESS # If CONTENT_TYPE_GATING is enabled use the following logic to determine whether a user should have FULL_ACCESS # or LIMITED_ACCESS course_mode = apps.get_model('course_modes.CourseMode') modes = course_mode.modes_for_course(course_key, include_expired=True, only_selectable=False) modes_dict = {mode.slug: mode for mode in modes} # If there is no verified mode, all users are granted FULL_ACCESS if not course_mode.has_verified_mode(modes_dict): return cls.FULL_ACCESS course_enrollment = apps.get_model('student.CourseEnrollment') mode_slug, is_active = course_enrollment.enrollment_mode_for_user(user, course_key) if mode_slug and is_active: course_mode = course_mode.mode_for_course( course_key, mode_slug, modes=modes, ) if course_mode is None: LOG.error( "User %s is in an unknown CourseMode '%s'" " for course %s. Granting full access to content for this user", user.username, mode_slug, course_key, ) return cls.FULL_ACCESS if mode_slug == CourseMode.AUDIT: return cls.LIMITED_ACCESS else: return cls.FULL_ACCESS else: # Unenrolled users don't get gated content return cls.LIMITED_ACCESS
def check_course_expired(user, course): """ Check if the course expired for the user. """ # masquerading course staff should always have access if get_course_masquerade(user, course.id): return ACCESS_GRANTED expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > expiration_date: return AuditExpiredError(user, course, expiration_date) return ACCESS_GRANTED
def check_course_expired(user, course): """ Check if the course expired for the user. """ # masquerading course staff should always have access if get_course_masquerade(user, course.id): return ACCESS_GRANTED if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id): return ACCESS_GRANTED expiration_date = get_user_course_expiration_date(user, course) if expiration_date and timezone.now() > expiration_date: return AuditExpiredError(user, course, expiration_date) return ACCESS_GRANTED
def get_group_for_user(cls, course_key, user, user_partition, **kwargs): # pylint: disable=unused-argument """ Returns the Group from the specified user partition to which the user is assigned, via enrollment mode. If a user is in a Credit mode, the Verified or Professional mode for the course is returned instead. If a course is using the Verified Track Cohorting pilot feature, this method returns None regardless of the user's enrollment mode. """ if is_course_using_cohort_instead(course_key): return None # First, check if we have to deal with masquerading. # If the current user is masquerading as a specific student, use the # same logic as normal to return that student's group. If the current # user is masquerading as a generic student in a specific group, then # return that group. if get_course_masquerade( user, course_key) and not is_masquerading_as_specific_student( user, course_key): return get_masquerading_user_group(course_key, user, user_partition) mode_slug, is_active = CourseEnrollment.enrollment_mode_for_user( user, course_key) if mode_slug and is_active: course_mode = CourseMode.mode_for_course( course_key, mode_slug, modes=CourseMode.modes_for_course(course_key, include_expired=True, only_selectable=False), ) if course_mode and CourseMode.is_credit_mode(course_mode): # We want the verified track even if the upgrade deadline has passed, since we # are determining what content to show the user, not whether the user can enroll # in the verified track. course_mode = CourseMode.verified_mode_for_course( course_key, include_expired=True) if not course_mode: course_mode = CourseMode.DEFAULT_MODE return Group(ENROLLMENT_GROUP_IDS[course_mode.slug]["id"], six.text_type(course_mode.name)) else: return None
def get_group_for_user(cls, course_key, user, user_partition, **kwargs): # pylint: disable=unused-argument """ Returns the Group for the specified user. """ # First, check if we have to deal with masquerading. # If the current user is masquerading as a specific student, use the # same logic as normal to return that student's group. If the current # user is masquerading as a generic student in a specific group, then # return that group. if get_course_masquerade( user, course_key) and not is_masquerading_as_specific_student( user, course_key): return get_masquerading_user_group(course_key, user, user_partition) # For now, treat everyone as a Full-access user, until we have the rest of the # feature gating logic in place. return cls.FULL_ACCESS
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Course Duration Limits are enabled for this enrollment. Course Duration Limits are enabled for an enrollment if they are enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) if user is None and enrollment is not None: user = enrollment.user if user and user.id: course_masquerade = get_course_masquerade(user, course_key) if course_masquerade: if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade): return False elif has_staff_roles(user, course_key): return False is_masquerading = get_course_masquerade(user, course_key) no_masquerade = is_masquerading is None student_masquerade = is_masquerading_as_specific_student(user, course_key) # check if user is in holdback if (no_masquerade or student_masquerade) and is_in_holdback(user): return False not_student_masquerade = is_masquerading and not student_masquerade # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today # When masquerading as a user group rather than a specific learner, # course duration limits will be on if they are on for the course. # When masquerading as a specific learner, course duration limits # will be on if they are currently on for the learner. if enrollment is None or not_student_masquerade: # we bypass enabled_for_course here and use enabled_as_of_datetime directly # because the correct_modes_for_fbe for FBE check contained in enabled_for_course # is redundant with checks done upstream of this code target_datetime = timezone.now() else: target_datetime = enrollment.created current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Course Duration Limits are enabled for this enrollment. Course Duration Limits are enabled for an enrollment if they are enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) # if the user is has a role of staff, instructor or beta tester their access should not expire if user is None and enrollment is not None: user = enrollment.user if user: course_masquerade = get_course_masquerade(user, course_key) if course_masquerade: verified_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.VERIFIED, {}).get('id') is_verified = (course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID and course_masquerade.group_id == verified_mode_id) is_full_access = (course_masquerade.user_partition_id == CONTENT_GATING_PARTITION_ID and course_masquerade.group_id == CONTENT_TYPE_GATE_GROUP_IDS['full_access']) is_staff = get_masquerade_role(user, course_key) == 'staff' if is_verified or is_full_access or is_staff: return False else: staff_role = CourseStaffRole(course_key).has_user(user) instructor_role = CourseInstructorRole(course_key).has_user(user) beta_tester_role = CourseBetaTesterRole(course_key).has_user(user) if staff_role or instructor_role or beta_tester_role: return False # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today if enrollment is None: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: # TODO: clean up as part of REV-100 experiment_data_holdback_key = EXPERIMENT_DATA_HOLDBACK_KEY.format(user) is_in_holdback = False no_masquerade = get_course_masquerade(user, course_key) is None student_masquerade = is_masquerading_as_specific_student(user, course_key) if user and (no_masquerade or student_masquerade): try: holdback_value = ExperimentData.objects.get( user=user, experiment_id=EXPERIMENT_ID, key=experiment_data_holdback_key, ).value is_in_holdback = holdback_value == 'True' except ExperimentData.DoesNotExist: pass if is_in_holdback: return False current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Course Duration Limits are enabled for this enrollment. Course Duration Limits are enabled for an enrollment if they are enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if enrollment is not None and (user is not None or course_key is not None): raise ValueError( 'Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError( 'Both user and course_key must be specified if no enrollment is provided' ) if enrollment is None and user is None and course_key is None: raise ValueError( 'At least one of enrollment or user and course_key must be specified' ) if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) # if the user is has a role of staff, instructor or beta tester their access should not expire if user is None and enrollment is not None: user = enrollment.user if user: course_masquerade = get_course_masquerade(user, course_key) if course_masquerade: verified_mode_id = settings.COURSE_ENROLLMENT_MODES.get( CourseMode.VERIFIED, {}).get('id') is_verified = (course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID and course_masquerade.group_id == verified_mode_id) is_full_access = ( course_masquerade.user_partition_id == CONTENT_GATING_PARTITION_ID and course_masquerade.group_id == CONTENT_TYPE_GATE_GROUP_IDS['full_access']) is_staff = get_masquerade_role(user, course_key) == 'staff' if is_verified or is_full_access or is_staff: return False else: staff_role = CourseStaffRole(course_key).has_user(user) instructor_role = CourseInstructorRole(course_key).has_user( user) beta_tester_role = CourseBetaTesterRole(course_key).has_user( user) if staff_role or instructor_role or beta_tester_role: return False # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today if enrollment is None: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: # TODO: clean up as part of REV-100 experiment_data_holdback_key = EXPERIMENT_DATA_HOLDBACK_KEY.format( user) is_in_holdback = False no_masquerade = get_course_masquerade(user, course_key) is None student_masquerade = is_masquerading_as_specific_student( user, course_key) if user and (no_masquerade or student_masquerade): try: holdback_value = ExperimentData.objects.get( user=user, experiment_id=EXPERIMENT_ID, key=experiment_data_holdback_key, ).value is_in_holdback = holdback_value == 'True' except ExperimentData.DoesNotExist: pass if is_in_holdback: return False current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime( target_datetime=enrollment.created)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Course Duration Limits are enabled for this enrollment. Course Duration Limits are enabled for an enrollment if they are enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if FEATURE_BASED_ENROLLMENT_GLOBAL_KILL_FLAG.is_enabled(): return False if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) if user is None and enrollment is not None: user = enrollment.user if user and user.id: course_masquerade = get_course_masquerade(user, course_key) if course_masquerade: if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade): return False elif has_staff_roles(user, course_key): return False is_masquerading = get_course_masquerade(user, course_key) no_masquerade = is_masquerading is None student_masquerade = is_masquerading_as_specific_student(user, course_key) # check if user is in holdback if (no_masquerade or student_masquerade) and is_in_holdback(user): return False not_student_masquerade = is_masquerading and not student_masquerade # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today # When masquerading as a user group rather than a specific learner, # course duration limits will be on if they are on for the course. # When masquerading as a specific learner, course duration limits # will be on if they are currently on for the learner. if enrollment is None or not_student_masquerade: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime(target_datetime=enrollment.created)
def get_group_for_user(cls, course_key, user, user_partition, **kwargs): # pylint: disable=unused-argument """ Returns the Group for the specified user. """ # First, check if we have to deal with masquerading. # If the current user is masquerading as a specific student, use the # same logic as normal to return that student's group. If the current # user is masquerading as a generic student in a specific group, then # return that group. course_masquerade = get_course_masquerade(user, course_key) if course_masquerade and not is_masquerading_as_specific_student(user, course_key): masquerade_group = get_masquerading_user_group(course_key, user, user_partition) if masquerade_group is not None: return masquerade_group else: audit_mode_id = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.AUDIT, {}).get('id') if course_masquerade.user_partition_id == ENROLLMENT_TRACK_PARTITION_ID: if course_masquerade.group_id != audit_mode_id: return cls.FULL_ACCESS else: return cls.LIMITED_ACCESS # For now, treat everyone as a Full-access user, until we have the rest of the # feature gating logic in place. if not ContentTypeGatingConfig.enabled_for_enrollment(user=user, course_key=course_key): return cls.FULL_ACCESS # If CONTENT_TYPE_GATING is enabled use the following logic to determine whether a user should have FULL_ACCESS # or LIMITED_ACCESS course_mode = apps.get_model('course_modes.CourseMode') modes = course_mode.modes_for_course(course_key, include_expired=True, only_selectable=False) modes_dict = {mode.slug: mode for mode in modes} # If there is no verified mode, all users are granted FULL_ACCESS if not course_mode.has_verified_mode(modes_dict): return cls.FULL_ACCESS # If the user is a beta tester for this course they are granted FULL_ACCESS if CourseBetaTesterRole(course_key).has_user(user): return cls.FULL_ACCESS course_enrollment = apps.get_model('student.CourseEnrollment') mode_slug, is_active = course_enrollment.enrollment_mode_for_user(user, course_key) if mode_slug and is_active: course_mode = course_mode.mode_for_course( course_key, mode_slug, modes=modes, ) if course_mode is None: LOG.error( "User %s is in an unknown CourseMode '%s'" " for course %s. Granting full access to content for this user", user.username, mode_slug, course_key, ) return cls.FULL_ACCESS if mode_slug == CourseMode.AUDIT: return cls.LIMITED_ACCESS else: return cls.FULL_ACCESS else: # Unenrolled users don't get gated content return cls.LIMITED_ACCESS
def get_group_for_user(cls, course_key, user, user_partition, use_cached=True): """ Returns the Group from the specified user partition to which the user is assigned, via their cohort membership and any mappings from cohorts to partitions / groups that might exist. If the user has not yet been assigned to a cohort, an assignment *might* be created on-the-fly, as determined by the course's cohort config. Any such side-effects will be triggered inside the call to cohorts.get_cohort(). If the user has no cohort mapping, or there is no (valid) cohort -> partition group mapping found, the function returns None. """ # First, check if we have to deal with masquerading. # If the current user is masquerading as a specific student, use the # same logic as normal to return that student's group. If the current # user is masquerading as a generic student in a specific group, then # return that group. if get_course_masquerade(user, course_key) and not is_masquerading_as_specific_student(user, course_key): return get_masquerading_user_group(course_key, user, user_partition) cohort = get_cohort(user, course_key, use_cached=use_cached) if cohort is None: # student doesn't have a cohort return None group_id, partition_id = get_group_info_for_cohort(cohort, use_cached=use_cached) if partition_id is None: # cohort isn't mapped to any partition group. return None if partition_id != user_partition.id: # if we have a match but the partition doesn't match the requested # one it means the mapping is invalid. the previous state of the # partition configuration may have been modified. log.warn( u"partition mismatch in CohortPartitionScheme: %r", { "requested_partition_id": user_partition.id, "found_partition_id": partition_id, "found_group_id": group_id, "cohort_id": cohort.id, } ) # fail silently return None try: return user_partition.get_group(group_id) except NoSuchUserPartitionGroupError: # if we have a match but the group doesn't exist in the partition, # it means the mapping is invalid. the previous state of the # partition configuration may have been modified. log.warn( u"group not found in CohortPartitionScheme: %r", { "requested_partition_id": user_partition.id, "requested_group_id": group_id, "cohort_id": cohort.id, }, exc_info=True ) # fail silently return None
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None): """ Return whether Content Type Gating is enabled for this enrollment. Content Type Gating is enabled for an enrollment if it is enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if enrollment is not None and (user is not None or course_key is not None): raise ValueError( 'Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError( 'Both user and course_key must be specified if no enrollment is provided' ) if enrollment is None and user is None and course_key is None: raise ValueError( 'At least one of enrollment or user and course_key must be specified' ) if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) if user is None and enrollment is not None: user = enrollment.user no_masquerade = get_course_masquerade(user, course_key) is None student_masquerade = is_masquerading_as_specific_student( user, course_key) # We can only use the user variable for the code below when the request is not in a masquerade state # or is masquerading as a specific user. # When a request is not in a masquerade state the user variable represents the correct user. # When a request is in a masquerade state and not masquerading as a specific user, # then then user variable will be the incorrect (original) user, not the masquerade user. # If a request is masquerading as a specific user, the user variable will represent the correct user. user_variable_represents_correct_user = (no_masquerade or student_masquerade) if user and user.id: # TODO: Move masquerade checks to enabled_for_enrollment from content_type_gating/partitions.py # TODO: Consolidate masquerade checks into shared function like has_staff_roles below if user_variable_represents_correct_user and has_staff_roles( user, course_key): return False # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today if enrollment is None: return cls.enabled_for_course(course_key=course_key, target_datetime=timezone.now()) else: # TODO: clean up as part of REV-100 experiment_data_holdback_key = EXPERIMENT_DATA_HOLDBACK_KEY.format( user) is_in_holdback = False if user and (user_variable_represents_correct_user): try: holdback_value = ExperimentData.objects.get( user=user, experiment_id=EXPERIMENT_ID, key=experiment_data_holdback_key, ).value is_in_holdback = holdback_value == 'True' except ExperimentData.DoesNotExist: pass if is_in_holdback: return False current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_datetime( target_datetime=enrollment.created)
def enabled_for_enrollment(cls, enrollment=None, user=None, course_key=None, user_partition=None): """ Return whether Content Type Gating is enabled for this enrollment. Content Type Gating is enabled for an enrollment if it is enabled for the course being enrolled in (either specifically, or via a containing context, such as the org, site, or globally), and if the configuration is specified to be ``enabled_as_of`` before the enrollment was created. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: enrollment: The enrollment being queried. user: The user being queried. course_key: The CourseKey of the course being queried. """ if enrollment is not None and (user is not None or course_key is not None): raise ValueError('Specify enrollment or user/course_key, but not both') if enrollment is None and (user is None or course_key is None): raise ValueError('Both user and course_key must be specified if no enrollment is provided') if enrollment is None and user is None and course_key is None: raise ValueError('At least one of enrollment or user and course_key must be specified') if course_key is None: course_key = enrollment.course_id if enrollment is None: enrollment = CourseEnrollment.get_enrollment(user, course_key) if user is None and enrollment is not None: user = enrollment.user course_masquerade = get_course_masquerade(user, course_key) no_masquerade = course_masquerade is None student_masquerade = is_masquerading_as_specific_student(user, course_key) user_variable_represents_correct_user = (no_masquerade or student_masquerade) if course_masquerade: if cls.has_full_access_role_in_masquerade(user, course_key, course_masquerade, student_masquerade, user_partition): return False # When a request is not in a masquerade state the user variable represents the correct user. elif user and user.id and has_staff_roles(user, course_key): return False # check if user is in holdback if user_variable_represents_correct_user and is_in_holdback(user): return False if not correct_modes_for_fbe(course_key, enrollment, user): return False # enrollment might be None if the user isn't enrolled. In that case, # return enablement as if the user enrolled today # Also, ignore enrollment creation date if the user is masquerading. if enrollment is None or course_masquerade: target_datetime = timezone.now() else: target_datetime = enrollment.created current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_datetime(target_datetime=target_datetime)