def get(self, block, name, default): if not CONTENT_TYPE_GATING_FLAG.is_enabled(): return default if name != 'group_access': return default graded = getattr(block, 'graded', False) has_score = block.has_score weight_not_zero = getattr(block, 'weight', 0) != 0 problem_eligible_for_content_gating = graded and has_score and weight_not_zero if not problem_eligible_for_content_gating: return default # Read the group_access from the fallback field-data service with disable_overrides(): original_group_access = block.group_access if original_group_access is None: original_group_access = {} original_group_access.setdefault( CONTENT_GATING_PARTITION_ID, [settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']]) return original_group_access
def create_content_gating_partition(course): """ Create and return the Content Gating user partition. """ if not (CONTENT_TYPE_GATING_FLAG.is_enabled() or CONTENT_TYPE_GATING_STUDIO_UI_FLAG.is_enabled()): return None try: content_gate_scheme = UserPartition.get_scheme("content_type_gate") except UserPartitionError: LOG.warning("No 'content_type_gate' scheme registered, ContentTypeGatingPartitionScheme will not be created.") return None used_ids = set(p.id for p in course.user_partitions) if CONTENT_GATING_PARTITION_ID in used_ids: # It's possible for course authors to add arbitrary partitions via XML import. If they do, and create a # partition with id 51, it will collide with the Content Gating Partition. We'll catch that here, and # then fix the course content as needed (or get the course team to). LOG.warning( "Can't add 'content_type_gate' partition, as ID {id} is assigned to {partition} in course {course}.".format( id=CONTENT_GATING_PARTITION_ID, partition=_get_partition_from_id(course.user_partitions, CONTENT_GATING_PARTITION_ID).name, course=unicode(course.id) ) ) return None partition = content_gate_scheme.create_user_partition( id=CONTENT_GATING_PARTITION_ID, name=_(u"Feature-based Enrollments"), description=_(u"Partition for segmenting users by access to gated content types"), parameters={"course_id": unicode(course.id)} ) return partition
def get_queryset(self): api_version = self.kwargs.get('api_version') enrollments = self.queryset.filter( user__username=self.kwargs['username'], is_active=True).order_by('created').reverse() org = self.request.query_params.get('org', None) if api_version == API_V05: # for v0.5 don't return expired courses return [ enrollment for enrollment in enrollments if enrollment.course_overview and self.is_org(org, enrollment.course_overview.org) and is_mobile_available_for_user(self.request.user, enrollment.course_overview) and not self.hide_course_for_enrollment_fee_experiment( self.request.user, enrollment) and ( not CONTENT_TYPE_GATING_FLAG.is_enabled() or check_course_expired(self.request.user, enrollment. course) == ACCESS_GRANTED) ] else: # return all courses, with associated expiration return [ enrollment for enrollment in enrollments if enrollment.course_overview and self.is_org(org, enrollment.course_overview.org) and is_mobile_available_for_user(self.request.user, enrollment.course_overview) ]
def enabled_for_course(cls, course_key, target_datetime=None): """ Return whether Course Duration Limits are enabled for this course as of a particular date. Course Duration Limits are enabled for a course on a date if they are enabled 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 ``target_datetime``. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: course_key: The CourseKey of the course being queried. target_datetime: The datetime to checked enablement as of. Defaults to the current date and time. """ if FEATURE_BASED_ENROLLMENT_GLOBAL_KILL_FLAG.is_enabled(): return False if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if target_datetime is None: target_datetime = timezone.now() current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
def get_course_block_access_transformers(user): """ Default list of transformers for manipulating course block structures based on the user's access to the course blocks. Arguments: user (django.contrib.auth.models.User) - User object for which the block structure is to be transformed. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): # [REV/Revisit] remove this duplicated code when flag is removed course_block_access_transformers = [ library_content.ContentLibraryTransformer(), start_date.StartDateTransformer(), ContentTypeGateTransformer(), user_partitions.UserPartitionTransformer(), visibility.VisibilityTransformer(), ] else: course_block_access_transformers = [ library_content.ContentLibraryTransformer(), start_date.StartDateTransformer(), user_partitions.UserPartitionTransformer(), visibility.VisibilityTransformer(), ] if has_individual_student_override_provider(): course_block_access_transformers += [ load_override_data.OverrideDataTransformer(user) ] return course_block_access_transformers
def can_load(): """ Can this user load this course? NOTE: this is not checking whether user is actually enrolled in the course. """ # N.B. I'd love a better way to handle this pattern, without breaking the # shortcircuiting logic. Maybe AccessResponse needs to grow a # fluent interface? # # return ( # _visible_to_nonstaff_users(courselike).and( # check_course_open_for_learner, user, courselike # ).and( # _can_view_courseware_with_prerequisites, user, courselike # ) # ).or( # _has_staff_access_to_descriptor, user, courselike, courselike.id # ) visible_to_nonstaff = _visible_to_nonstaff_users(courselike) if not visible_to_nonstaff: staff_access = _has_staff_access_to_descriptor( user, courselike, courselike.id) if staff_access: return staff_access else: return visible_to_nonstaff open_for_learner = check_course_open_for_learner(user, courselike) if not open_for_learner: staff_access = _has_staff_access_to_descriptor( user, courselike, courselike.id) if staff_access: return staff_access else: return open_for_learner view_with_prereqs = _can_view_courseware_with_prerequisites( user, courselike) if not view_with_prereqs: staff_access = _has_staff_access_to_descriptor( user, courselike, courselike.id) if staff_access: return staff_access else: return view_with_prereqs if CONTENT_TYPE_GATING_FLAG.is_enabled(): has_not_expired = check_course_expired(user, courselike) if not has_not_expired: staff_access = _has_staff_access_to_descriptor( user, courselike, courselike.id) if staff_access: return staff_access else: return has_not_expired return ACCESS_GRANTED
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 enabled_as_of_datetime(self, target_datetime): """ Return whether this Content Type Gating configuration context is enabled as of a date and time. Arguments: target_datetime (:class:`datetime.datetime`): The datetime that ``enabled_as_of`` must be equal to or before """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True # Explicitly cast this to bool, so that when self.enabled is None the method doesn't return None return bool(self.enabled and self.enabled_as_of <= target_datetime)
def enabled_as_of_date(self, target_date): """ Return whether this Content Type Gating configuration context is enabled as of a date. Arguments: target_date (:class:`datetime.date`): The date that ``enabled_as_of`` must be equal to or before """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True # Explicitly cast this to bool, so that when self.enabled is None the method doesn't return None return bool(self.enabled and self.enabled_as_of <= target_date)
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_date=datetime.utcnow().date()) else: current_config = cls.current(course_key=enrollment.course_id) return current_config.enabled_as_of_date( target_date=enrollment.created.date())
def enabled_as_of_datetime(self, target_datetime): """ Return whether this Course Duration Limit configuration context is enabled as of a date and time. Arguments: target_datetime (:class:`datetime.datetime`): The datetime that ``enabled_as_of`` must be equal to or before """ if FEATURE_BASED_ENROLLMENT_GLOBAL_KILL_FLAG.is_enabled(): return True if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True # Explicitly cast this to bool, so that when self.enabled is None the method doesn't return None return bool(self.enabled and self.enabled_as_of <= target_datetime)
def register_course_expired_message(request, course): """ Add a banner notifying the user of the user course expiration date if it exists. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): expiration_date = get_user_course_expiration_date(request.user, course) if expiration_date: upgrade_message = _( 'Your access to this course expires on {expiration_date}. \ <a href="{upgrade_link}">Upgrade now</a> for unlimited access.' ) PageLevelMessages.register_info_message( request, HTML(upgrade_message).format( expiration_date=expiration_date.strftime('%b %-d'), upgrade_link=verified_upgrade_deadline_link( user=request.user, course=course)))
def get(self, block, name, default): if not CONTENT_TYPE_GATING_FLAG.is_enabled(): return default if name != 'group_access': return default if not (getattr(block, 'graded', False) and block.has_score): return default # Read the group_access from the fallback field-data service with disable_overrides(): original_group_access = block.group_access if original_group_access is None: original_group_access = {} original_group_access.setdefault( CONTENT_GATING_PARTITION_ID, [settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']]) return original_group_access
def get(self, block, name, default): if not CONTENT_TYPE_GATING_FLAG.is_enabled(): return default if name != 'group_access': return default graded = getattr(block, 'graded', False) has_score = block.has_score weight_not_zero = getattr(block, 'weight', 0) != 0 problem_eligible_for_content_gating = graded and has_score and weight_not_zero if not problem_eligible_for_content_gating: return default # We want to fetch the value set by course authors since it should take precedence. # We cannot simply call "block.group_access" to fetch that value even if we disable # field overrides since it will set the group access field to "dirty" with # the value read from the course content. Since most content does not have any # value for this field it will usually be the default empty dict. This field # override changes the value, however, resulting in the LMS thinking that the # field data needs to be written back out to the store. This doesn't work, # however, since this is a read-only setting in the LMS context. After this # call to get() returns, the _dirty_fields dict will be set correctly to contain # the value from this field override. This prevents the system from attempting # to save the overridden value when it thinks it has changed when it hasn't. original_group_access = None if self.fallback_field_data.has(block, 'group_access'): raw_value = self.fallback_field_data.get(block, 'group_access') group_access_field = block.fields.get('group_access') if group_access_field is not None: original_group_access = group_access_field.from_json(raw_value) if original_group_access is None: original_group_access = {} original_group_access.setdefault( CONTENT_GATING_PARTITION_ID, [settings.CONTENT_TYPE_GATE_GROUP_IDS['full_access']] ) return original_group_access
def enabled_for_course(cls, course_key, target_datetime=None): """ Return whether Content Type Gating is enabled for this course as of a particular date. Content Type Gating is enabled for a course on a date if it is enabled 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 ``target_datetime``. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: course_key: The CourseKey of the course being queried. target_datetime: The datetime to checked enablement as of. Defaults to the current date and time. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if target_datetime is None: target_datetime = timezone.now() current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_datetime(target_datetime=target_datetime)
def enabled_for_course(cls, course_key, target_date=None): """ Return whether Content Type Gating is enabled for this course as of a particular date. Content Type Gating is enabled for a course on a date if it is enabled 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 ``target_date``. Only one of enrollment and (user, course_key) may be specified at a time. Arguments: course_key: The CourseKey of the course being queried. target_date: The date to checked enablement as of. Defaults to the current date. """ if CONTENT_TYPE_GATING_FLAG.is_enabled(): return True if target_date is None: target_date = datetime.utcnow().date() current_config = cls.current(course_key=course_key) return current_config.enabled_as_of_date(target_date=target_date)
def get_visibility_partition_info(xblock, course=None): """ Retrieve user partition information for the component visibility editor. This pre-processes partition information to simplify the template. Arguments: xblock (XBlock): The component being edited. course (XBlock): The course descriptor. If provided, uses this to look up the user partitions instead of loading the course. This is useful if we're calling this function multiple times for the same course want to minimize queries to the modulestore. Returns: dict """ selectable_partitions = [] # We wish to display enrollment partitions before cohort partitions. enrollment_user_partitions = get_user_partition_info(xblock, schemes=["enrollment_track"], course=course) # For enrollment partitions, we only show them if there is a selected group or # or if the number of groups > 1. for partition in enrollment_user_partitions: if len(partition["groups"]) > 1 or any(group["selected"] for group in partition["groups"]): selectable_partitions.append(partition) flag_enabled = CONTENT_TYPE_GATING_FLAG.is_enabled() course_key = xblock.scope_ids.usage_id.course_key is_library = isinstance(course_key, LibraryLocator) if not is_library and ( flag_enabled or ContentTypeGatingConfig.current(course_key=course_key).studio_override_enabled ): selectable_partitions += get_user_partition_info(xblock, schemes=["content_type_gate"], course=course) # Now add the cohort user partitions. selectable_partitions = selectable_partitions + get_user_partition_info(xblock, schemes=["cohort"], course=course) # Find the first partition with a selected group. That will be the one initially enabled in the dialog # (if the course has only been added in Studio, only one partition should have a selected group). selected_partition_index = -1 # At the same time, build up all the selected groups as they are displayed in the dialog title. selected_groups_label = '' for index, partition in enumerate(selectable_partitions): for group in partition["groups"]: if group["selected"]: if len(selected_groups_label) == 0: selected_groups_label = group['name'] else: # Translators: This is building up a list of groups. It is marked for translation because of the # comma, which is used as a separator between each group. selected_groups_label = _('{previous_groups}, {current_group}').format( previous_groups=selected_groups_label, current_group=group['name'] ) if selected_partition_index == -1: selected_partition_index = index return { "selectable_partitions": selectable_partitions, "selected_partition_index": selected_partition_index, "selected_groups_label": selected_groups_label, }
def get(self, request, course_id, error=None): """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_ip(request), url=request.path) if embargo_redirect: return redirect(embargo_redirect) enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user( request.user, course_key) 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 non-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") verify_url = reverse('verify_student_start_flow', kwargs={'course_id': unicode(course_key)}) redirect_url = "{url}?purchase_workflow={workflow}".format( url=verify_url, workflow=purchase_workflow) 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 redirect(reverse('dashboard')) # 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]): # If the course has started redirect to course home instead if course.has_started(): return redirect( reverse('openedx.course_experience.course_home', kwargs={'course_id': course_key})) return redirect(reverse('dashboard')) donation_for_course = request.session.get("donation_for_course", {}) chosen_price = donation_for_course.get(unicode(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 = urllib.urlencode({'course_closed': enrollment_end_date}) return redirect('{0}?{1}'.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 univerity 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 = text_type(course_key) bundle_data = {} bundles_on_track_selection = WaffleFlag( WaffleFlagNamespace(name=u'experiments'), u'bundles_on_track_selection') if bundles_on_track_selection.is_enabled(): # enrollment in the course on this page current_enrollment = list( CourseEnrollment.enrollments_for_user( request.user).filter(course_id=course_key)) if current_enrollment: meter = ProgramProgressMeter(request.site, request.user, enrollments=current_enrollment) meter_inverted_programs = meter.invert_programs() if len(meter_inverted_programs) > 0: # program for the course on this page programs_for_course = meter_inverted_programs.get( course_id) if programs_for_course: program_for_course = programs_for_course[0] program_uuid = program_for_course.get('uuid') if program_for_course: # program data with bundle info program_data = ProgramDataExtender( program_for_course, request.user, mobile_only=False).extend() skus = program_data.get('skus') ecommerce_service = EcommerceService() program_bundle_url = ecommerce_service.get_checkout_page_url( *skus, program_uuid=program_uuid) bundle_data = { 'program_marketing_site_url': program_data.get('marketing_url'), 'program_bundle_url': program_bundle_url, 'discount_data': program_data.get('discount_data'), 'program_type': program_data.get('type'), 'program_title': program_data.get('title'), 'program_price': program_data.get('full_program_price'), } context = { "bundle_data": bundle_data, "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": CONTENT_TYPE_GATING_FLAG.is_enabled(), } context.update( get_experiment_user_metadata_context( course, request.user, )) 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() ] context["currency"] = verified_mode.currency.upper() context["min_price"] = verified_mode.min_price context["verified_name"] = verified_mode.name context["verified_description"] = verified_mode.description 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 return render_to_response("course_modes/choose.html", context)
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 get_visibility_partition_info(xblock, course=None): """ Retrieve user partition information for the component visibility editor. This pre-processes partition information to simplify the template. Arguments: xblock (XBlock): The component being edited. course (XBlock): The course descriptor. If provided, uses this to look up the user partitions instead of loading the course. This is useful if we're calling this function multiple times for the same course want to minimize queries to the modulestore. Returns: dict """ selectable_partitions = [] # We wish to display enrollment partitions before cohort partitions. enrollment_user_partitions = get_user_partition_info( xblock, schemes=["enrollment_track"], course=course) # For enrollment partitions, we only show them if there is a selected group or # or if the number of groups > 1. for partition in enrollment_user_partitions: if len(partition["groups"]) > 1 or any( group["selected"] for group in partition["groups"]): selectable_partitions.append(partition) flag_enabled = CONTENT_TYPE_GATING_FLAG.is_enabled() course_key = xblock.scope_ids.usage_id.course_key is_library = isinstance(course_key, LibraryLocator) if not is_library and (flag_enabled or ContentTypeGatingConfig.current( course_key=course_key).studio_override_enabled): selectable_partitions += get_user_partition_info( xblock, schemes=["content_type_gate"], course=course) # Now add the cohort user partitions. selectable_partitions = selectable_partitions + get_user_partition_info( xblock, schemes=["cohort"], course=course) # Find the first partition with a selected group. That will be the one initially enabled in the dialog # (if the course has only been added in Studio, only one partition should have a selected group). selected_partition_index = -1 # At the same time, build up all the selected groups as they are displayed in the dialog title. selected_groups_label = '' for index, partition in enumerate(selectable_partitions): for group in partition["groups"]: if group["selected"]: if len(selected_groups_label) == 0: selected_groups_label = group['name'] else: # Translators: This is building up a list of groups. It is marked for translation because of the # comma, which is used as a separator between each group. selected_groups_label = _( '{previous_groups}, {current_group}').format( previous_groups=selected_groups_label, current_group=group['name']) if selected_partition_index == -1: selected_partition_index = index return { "selectable_partitions": selectable_partitions, "selected_partition_index": selected_partition_index, "selected_groups_label": selected_groups_label, }
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 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): """ 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, 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 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 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)