Repository navigation
Course visibility options #18537
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Course visibility options #18537
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,9 +32,10 @@ | |
| from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY | ||
| from openedx.core.djangoapps.user_api.preferences.api import get_user_preference | ||
| from openedx.core.djangoapps.util.user_messages import PageLevelMessages | ||
| from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace, WaffleFlagNamespace, CourseWaffleFlag | ||
| from openedx.core.djangoapps.waffle_utils import WaffleSwitchNamespace | ||
| from openedx.core.djangolib.markup import HTML, Text | ||
| from openedx.features.course_experience import COURSE_OUTLINE_PAGE_FLAG, default_course_url_name | ||
| from openedx.features.course_experience import COURSE_OUTLINE_PAGE_FLAG, default_course_url_name, \ | ||
| COURSE_ENABLE_ANONYMOUS_ACCESS_FLAG | ||
| from openedx.features.course_experience.views.course_sock import CourseSockFragmentView | ||
| from openedx.features.enterprise_support.api import data_sharing_consent_required | ||
| from shoppingcart.models import CourseRegistrationCode | ||
|
|
@@ -69,8 +70,7 @@ class CoursewareIndex(View): | |
|
|
||
| @cached_property | ||
| def enable_anonymous_courseware_access(self): | ||
| waffle_flag = CourseWaffleFlag(WaffleFlagNamespace(name='seo'), 'enable_anonymous_courseware_access') | ||
| return waffle_flag.is_enabled(self.course_key) | ||
| return COURSE_ENABLE_ANONYMOUS_ACCESS_FLAG.is_enabled(self.course_key) | ||
|
|
||
| @method_decorator(ensure_csrf_cookie) | ||
| @method_decorator(cache_control(no_cache=True, no_store=True, must_revalidate=True)) | ||
|
|
@@ -118,6 +118,9 @@ def get(self, request, course_id, chapter=None, section=None, position=None): | |
| depth=CONTENT_DEPTH, | ||
| check_if_enrolled=not self.enable_anonymous_courseware_access, | ||
| ) | ||
| if not (request.user.is_authenticated or self.course.course_visibility == 'public'): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the check needs to be updated here too?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| return redirect_to_login(request.get_full_path()) | ||
|
|
||
| self.is_staff = has_access(request.user, 'staff', self.course) | ||
| self._setup_masquerade_for_effective_user() | ||
| return self.render(request) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,10 @@ | |
| # Waffle flag to enable the use of Bootstrap for course experience pages | ||
| USE_BOOTSTRAP_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'use_bootstrap', flag_undefined_default=True) | ||
|
|
||
| # Waffle flag to enable anonymous access to a course | ||
| SEO_WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='seo') | ||
| COURSE_ENABLE_ANONYMOUS_ACCESS_FLAG = CourseWaffleFlag(SEO_WAFFLE_FLAG_NAMESPACE, 'enable_anonymous_courseware_access') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be renamed to
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
|
||
|
|
||
| def course_home_page_title(course): # pylint: disable=unused-argument | ||
| """ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,8 +24,8 @@ | |
| from openedx.features.course_experience import ( | ||
| SHOW_REVIEWS_TOOL_FLAG, | ||
| SHOW_UPGRADE_MSG_ON_COURSE_HOME, | ||
| UNIFIED_COURSE_TAB_FLAG | ||
| ) | ||
| UNIFIED_COURSE_TAB_FLAG, | ||
| COURSE_ENABLE_ANONYMOUS_ACCESS_FLAG) | ||
| from student.models import CourseEnrollment | ||
| from student.tests.factories import UserFactory | ||
| from util.date_utils import strftime_localized | ||
|
|
@@ -217,32 +217,46 @@ def tearDown(self): | |
|
|
||
| @override_waffle_flag(SHOW_REVIEWS_TOOL_FLAG, active=True) | ||
| @ddt.data( | ||
| [CourseUserType.ANONYMOUS, 'To see course content'], | ||
| [CourseUserType.ENROLLED, None], | ||
| [CourseUserType.UNENROLLED, 'You must be enrolled in the course to see course content.'], | ||
| [CourseUserType.UNENROLLED_STAFF, 'You must be enrolled in the course to see course content.'], | ||
| [False, 'private', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
| [False, 'preview', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
| [False, 'public', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
| [True, 'private', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
| [True, 'preview', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
| [True, 'public', CourseUserType.ANONYMOUS, 'You must be enrolled in the course to see course content.'], | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will likely need a different message for this case but it is something the edX UX can recommend.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also add checks that |
||
| [False, 'private', CourseUserType.ENROLLED, None], | ||
| [False, 'private', CourseUserType.UNENROLLED, 'You must be enrolled in the course to see course content.'], | ||
| [False, 'private', CourseUserType.UNENROLLED_STAFF, | ||
| 'You must be enrolled in the course to see course content.'], | ||
| ) | ||
| @ddt.unpack | ||
| def test_home_page(self, user_type, expected_message): | ||
| def test_home_page(self, enable_anonymous_access, course_visibility, user_type, expected_message): | ||
| self.create_user_for_course(self.course, user_type) | ||
|
|
||
| # Render the course home page | ||
| url = course_home_url(self.course) | ||
| response = self.client.get(url) | ||
| with mock.patch('xmodule.course_module.CourseDescriptor.course_visibility', course_visibility): | ||
| # Test access with anonymous flag and course visibility | ||
| with override_waffle_flag(COURSE_ENABLE_ANONYMOUS_ACCESS_FLAG, enable_anonymous_access): | ||
| url = course_home_url(self.course) | ||
| response = self.client.get(url) | ||
|
|
||
| # Verify that the course tools and dates are always shown | ||
| self.assertContains(response, 'Course Tools') | ||
| self.assertContains(response, 'Today is') | ||
|
|
||
| # Verify that the outline, start button, course sock, and welcome message | ||
| # Verify that start button, course sock, and welcome message | ||
| # are only shown to enrolled users. | ||
| is_enrolled = user_type is CourseUserType.ENROLLED | ||
| is_unenrolled_staff = user_type is CourseUserType.UNENROLLED_STAFF | ||
| expected_count = 1 if (is_enrolled or is_unenrolled_staff) else 0 | ||
| self.assertContains(response, TEST_CHAPTER_NAME, count=expected_count) | ||
| self.assertContains(response, 'Start Course', count=expected_count) | ||
| expected_welcome = 1 if (is_enrolled or is_unenrolled_staff) else 0 | ||
| self.assertContains(response, 'Start Course', count=expected_welcome) | ||
| self.assertContains(response, 'Learn About Verified Certificate', count=(1 if is_enrolled else 0)) | ||
| self.assertContains(response, TEST_WELCOME_MESSAGE, count=expected_count) | ||
| self.assertContains(response, TEST_WELCOME_MESSAGE, count=expected_welcome) | ||
|
|
||
| # Verify the outline is shown to enrolled users, unenrolled_staff and anonymous users if allowed | ||
| is_public = course_visibility == 'public' and enable_anonymous_access | ||
| is_preview = course_visibility == 'preview' and enable_anonymous_access | ||
| expected_chapter = 1 if (is_public or is_preview) else expected_welcome | ||
| self.assertContains(response, TEST_CHAPTER_NAME, count=expected_chapter) | ||
|
|
||
| # Verify that the expected message is shown to the user | ||
| self.assertContains(response, '<div class="user-messages">', count=1 if expected_message else 0) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -156,13 +156,14 @@ def mark_last_accessed(user, course_key, block): | |
| course_outline_root_block = all_blocks['blocks'].get(all_blocks['root'], None) | ||
| if course_outline_root_block: | ||
| populate_children(course_outline_root_block, all_blocks['blocks']) | ||
| set_last_accessed_default(course_outline_root_block) | ||
|
|
||
| mark_blocks_completed( | ||
| block=course_outline_root_block, | ||
| user=request.user, | ||
| course_key=course_key | ||
| ) | ||
| if request.user.is_authenticated: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would need an update too.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| set_last_accessed_default(course_outline_root_block) | ||
| mark_blocks_completed( | ||
| block=course_outline_root_block, | ||
| user=request.user, | ||
| course_key=course_key | ||
| ) | ||
| return course_outline_root_block | ||
|
|
||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since now we are using this behavior for unenrolled users as well, can you also check before enrolling the user that they see what anonymous users see?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍