Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
81d8c40e
Commit
81d8c40e
authored
Sep 19, 2014
by
John Eskew
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5281 from edx/adam/hide-tabs-if-not-enrolled-rebase-2
Deployed as hotfix
parents
6bf52074
0a385544
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
295 additions
and
45 deletions
+295
-45
common/djangoapps/embargo/tests/test_middleware.py
+2
-2
common/lib/xmodule/xmodule/tabs.py
+37
-18
common/lib/xmodule/xmodule/tests/test_tabs.py
+77
-12
lms/djangoapps/courseware/courses.py
+13
-1
lms/djangoapps/courseware/middleware.py
+23
-0
lms/djangoapps/courseware/tests/test_about.py
+13
-0
lms/djangoapps/courseware/tests/test_course_info.py
+8
-1
lms/djangoapps/courseware/tests/test_middleware.py
+53
-0
lms/djangoapps/courseware/tests/test_tabs.py
+0
-1
lms/djangoapps/courseware/views.py
+16
-6
lms/djangoapps/django_comment_client/forum/tests.py
+24
-0
lms/djangoapps/django_comment_client/forum/views.py
+1
-1
lms/envs/common.py
+3
-0
lms/templates/courseware/course_navigation.html
+5
-1
lms/templates/courseware/info.html
+19
-1
lms/templates/help_modal.html
+1
-1
No files found.
common/djangoapps/embargo/tests/test_middleware.py
View file @
81d8c40e
...
...
@@ -260,12 +260,12 @@ class EmbargoMiddlewareTests(ModuleStoreTestCase):
profile
.
save
()
# Warm the cache
with
self
.
assertNumQueries
(
1
4
):
with
self
.
assertNumQueries
(
1
6
):
self
.
client
.
get
(
self
.
embargoed_page
)
# Access the page multiple times, but expect that we hit
# the database to check the user's profile only once
with
self
.
assertNumQueries
(
8
):
with
self
.
assertNumQueries
(
10
):
self
.
client
.
get
(
self
.
embargoed_page
)
def
test_embargo_profile_country_db_null
(
self
):
...
...
common/lib/xmodule/xmodule/tabs.py
View file @
81d8c40e
...
...
@@ -57,7 +57,7 @@ class CourseTab(object): # pylint: disable=incomplete-protocol
self
.
link_func
=
link_func
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
# pylint: disable=unused-argument
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
# pylint: disable=unused-argument
"""
Determines whether the tab should be displayed in the UI for the given course and a particular user.
This method is to be overridden by subclasses when applicable. The base class implementation
...
...
@@ -78,6 +78,8 @@ class CourseTab(object): # pylint: disable=incomplete-protocol
is_user_staff: Indicates whether the user has staff access to the course. If the tab is of
type StaffTab and this value is False, then can_display will return False.
is_user_enrolled: Indicates whether the user is enrolled in the course
Returns:
A boolean value to indicate whether this instance of the tab should be displayed to a
given user for the given course.
...
...
@@ -212,7 +214,7 @@ class AuthenticatedCourseTab(CourseTab):
"""
Abstract class for tabs that can be accessed by only authenticated users.
"""
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
return
is_user_authenticated
...
...
@@ -220,9 +222,17 @@ class StaffTab(AuthenticatedCourseTab):
"""
Abstract class for tabs that can be accessed by only users with staff access.
"""
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
# pylint: disable=unused-argument
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
# pylint: disable=unused-argument
return
is_user_staff
class
EnrolledOrStaffTab
(
CourseTab
):
"""
Abstract class for tabs that can be accessed by only users with staff access
or users enrolled in the course.
"""
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
# pylint: disable=unused-argument
return
is_user_authenticated
and
(
is_user_staff
or
is_user_enrolled
)
class
HideableTab
(
CourseTab
):
"""
...
...
@@ -262,7 +272,7 @@ class HideableTab(CourseTab):
return
self
.
is_hidden
==
other
.
get
(
'is_hidden'
,
False
)
class
CoursewareTab
(
Course
Tab
):
class
CoursewareTab
(
EnrolledOrStaff
Tab
):
"""
A tab containing the course content.
"""
...
...
@@ -300,7 +310,7 @@ class CourseInfoTab(CourseTab):
return
super
(
CourseInfoTab
,
cls
)
.
validate
(
tab_dict
,
raise_error
)
and
need_name
(
tab_dict
,
raise_error
)
class
ProgressTab
(
AuthenticatedCourse
Tab
):
class
ProgressTab
(
EnrolledOrStaff
Tab
):
"""
A tab containing information about the authenticated user's progress.
"""
...
...
@@ -315,8 +325,11 @@ class ProgressTab(AuthenticatedCourseTab):
link_func
=
link_reverse_func
(
self
.
type
),
)
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
return
not
course
.
hide_progress_tab
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
super_can_display
=
super
(
ProgressTab
,
self
)
.
can_display
(
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
)
return
super_can_display
and
not
course
.
hide_progress_tab
@classmethod
def
validate
(
cls
,
tab_dict
,
raise_error
=
True
):
...
...
@@ -339,15 +352,17 @@ class WikiTab(HideableTab):
tab_dict
=
tab_dict
,
)
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
return
settings
.
WIKI_ENABLED
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
return
settings
.
WIKI_ENABLED
and
(
course
.
allow_public_wiki_access
or
is_user_enrolled
or
is_user_staff
)
@classmethod
def
validate
(
cls
,
tab_dict
,
raise_error
=
True
):
return
super
(
WikiTab
,
cls
)
.
validate
(
tab_dict
,
raise_error
)
and
need_name
(
tab_dict
,
raise_error
)
class
DiscussionTab
(
Course
Tab
):
class
DiscussionTab
(
EnrolledOrStaff
Tab
):
"""
A tab only for the new Berkeley discussion forums.
"""
...
...
@@ -362,8 +377,11 @@ class DiscussionTab(CourseTab):
link_func
=
link_reverse_func
(
'django_comment_client.forum.views.forum_form_discussion'
),
)
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
return
settings
.
FEATURES
.
get
(
'ENABLE_DISCUSSION_SERVICE'
)
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
super_can_display
=
super
(
DiscussionTab
,
self
)
.
can_display
(
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
)
return
settings
.
FEATURES
.
get
(
'ENABLE_DISCUSSION_SERVICE'
)
and
super_can_display
@classmethod
def
validate
(
cls
,
tab_dict
,
raise_error
=
True
):
...
...
@@ -529,7 +547,7 @@ class TextbookTabs(TextbookTabsBase):
tab_id
=
self
.
type
,
)
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
return
settings
.
FEATURES
.
get
(
'ENABLE_TEXTBOOK'
)
def
items
(
self
,
course
):
...
...
@@ -642,7 +660,7 @@ class SyllabusTab(CourseTab):
"""
type
=
'syllabus'
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
return
hasattr
(
course
,
'syllabus_present'
)
and
course
.
syllabus_present
def
__init__
(
self
,
tab_dict
=
None
):
# pylint: disable=unused-argument
...
...
@@ -660,7 +678,7 @@ class NotesTab(AuthenticatedCourseTab):
"""
type
=
'notes'
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
def
can_display
(
self
,
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
return
settings
.
FEATURES
.
get
(
'ENABLE_STUDENT_NOTES'
)
def
__init__
(
self
,
tab_dict
=
None
):
...
...
@@ -773,6 +791,7 @@ class CourseTabList(List):
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
True
,
is_user_enrolled
=
False
):
"""
Generator method for iterating through all tabs that can be displayed for the given course and
...
...
@@ -780,7 +799,7 @@ class CourseTabList(List):
"""
for
tab
in
course
.
tabs
:
if
tab
.
can_display
(
course
,
settings
,
is_user_authenticated
,
is_user_staff
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
)
and
(
not
tab
.
is_hideable
or
not
tab
.
is_hidden
):
if
tab
.
is_collection
:
for
item
in
tab
.
items
(
course
):
...
...
@@ -788,7 +807,7 @@ class CourseTabList(List):
else
:
yield
tab
instructor_tab
=
InstructorTab
()
if
instructor_tab
.
can_display
(
course
,
settings
,
is_user_authenticated
,
is_user_staff
):
if
instructor_tab
.
can_display
(
course
,
settings
,
is_user_authenticated
,
is_user_staff
,
is_user_enrolled
):
yield
instructor_tab
@staticmethod
...
...
@@ -801,7 +820,7 @@ class CourseTabList(List):
with the provided settings.
"""
for
tab
in
course
.
tabs
:
if
tab
.
can_display
(
course
,
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
True
):
if
tab
.
can_display
(
course
,
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
True
,
is_user_enrolled
=
True
):
if
tab
.
is_collection
and
not
len
(
list
(
tab
.
items
(
course
))):
# do not yield collections that have no items
continue
...
...
common/lib/xmodule/xmodule/tests/test_tabs.py
View file @
81d8c40e
...
...
@@ -90,22 +90,42 @@ class TabTestCase(unittest.TestCase):
deserialized_tab
=
tab
.
from_json
(
serialized_tab
)
self
.
assertEquals
(
serialized_tab
,
deserialized_tab
)
def
check_can_display_results
(
self
,
tab
,
expected_value
=
True
,
for_authenticated_users_only
=
False
,
for_staff_only
=
False
):
def
check_can_display_results
(
self
,
tab
,
expected_value
=
True
,
for_authenticated_users_only
=
False
,
for_staff_only
=
False
,
for_enrolled_users_only
=
False
):
"""Checks can display results for various users"""
if
for_staff_only
:
self
.
assertEquals
(
expected_value
,
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
False
,
is_user_staff
=
True
)
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
True
,
is_user_enrolled
=
True
)
)
if
for_authenticated_users_only
:
self
.
assertEquals
(
expected_value
,
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
False
)
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
False
,
is_user_enrolled
=
False
)
)
if
not
for_staff_only
and
not
for_authenticated_users_only
and
not
for_enrolled_users_only
:
self
.
assertEquals
(
expected_value
,
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
False
,
is_user_staff
=
False
,
is_user_enrolled
=
False
)
)
if
not
for_staff_only
and
not
for_authenticat
ed_users_only
:
if
for_enroll
ed_users_only
:
self
.
assertEquals
(
expected_value
,
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
False
,
is_user_staff
=
False
)
tab
.
can_display
(
self
.
course
,
self
.
settings
,
is_user_authenticated
=
True
,
is_user_staff
=
False
,
is_user_enrolled
=
True
)
)
def
check_get_and_set_methods
(
self
,
tab
):
...
...
@@ -147,11 +167,15 @@ class ProgressTestCase(TabTestCase):
self
.
course
.
hide_progress_tab
=
False
tab
=
self
.
check_progress_tab
()
self
.
check_can_display_results
(
tab
,
for_authenticated_users_only
=
True
)
self
.
check_can_display_results
(
tab
,
for_staff_only
=
True
,
for_enrolled_users_only
=
True
)
self
.
course
.
hide_progress_tab
=
True
self
.
check_progress_tab
()
self
.
check_can_display_results
(
tab
,
for_authenticated_users_only
=
True
,
expected_value
=
False
)
self
.
check_can_display_results
(
tab
,
for_staff_only
=
True
,
for_enrolled_users_only
=
True
,
expected_value
=
False
)
class
WikiTestCase
(
TabTestCase
):
...
...
@@ -167,13 +191,25 @@ class WikiTestCase(TabTestCase):
invalid_dict_tab
=
self
.
fake_dict_tab
,
)
def
test_wiki_enabled
(
self
):
"""Test wiki tab when Enabled setting is True"""
def
test_wiki_enabled_and_public
(
self
):
"""
Test wiki tab when Enabled setting is True and the wiki is open to
the public.
"""
self
.
settings
.
WIKI_ENABLED
=
True
self
.
course
.
allow_public_wiki_access
=
True
tab
=
self
.
check_wiki_tab
()
self
.
check_can_display_results
(
tab
)
def
test_wiki_enabled_and_not_public
(
self
):
"""
Test wiki when it is enabled but not open to the public
"""
self
.
settings
.
WIKI_ENABLED
=
True
self
.
course
.
allow_public_wiki_access
=
False
tab
=
self
.
check_wiki_tab
()
self
.
check_can_display_results
(
tab
,
for_enrolled_users_only
=
True
,
for_staff_only
=
True
)
def
test_wiki_enabled_false
(
self
):
"""Test wiki tab when Enabled setting is False"""
...
...
@@ -611,7 +647,14 @@ class DiscussionLinkTestCase(TabTestCase):
return
"default_discussion_link"
return
reverse_discussion_link
def
check_discussion
(
self
,
tab_list
,
expected_discussion_link
,
expected_can_display_value
,
discussion_link_in_course
=
""
):
def
check_discussion
(
self
,
tab_list
,
expected_discussion_link
,
expected_can_display_value
,
discussion_link_in_course
=
""
,
is_staff
=
True
,
is_enrolled
=
True
,
):
"""Helper function to verify whether the discussion tab exists and can be displayed"""
self
.
course
.
tabs
=
tab_list
self
.
course
.
discussion_link
=
discussion_link_in_course
...
...
@@ -619,7 +662,7 @@ class DiscussionLinkTestCase(TabTestCase):
self
.
assertEquals
(
(
discussion
is
not
None
and
discussion
.
can_display
(
self
.
course
,
self
.
settings
,
True
,
True
)
and
discussion
.
can_display
(
self
.
course
,
self
.
settings
,
True
,
is_staff
,
is_enrolled
)
and
(
discussion
.
link_func
(
self
.
course
,
self
.
_reverse
(
self
.
course
))
==
expected_discussion_link
)
),
expected_can_display_value
...
...
@@ -662,3 +705,25 @@ class DiscussionLinkTestCase(TabTestCase):
expected_discussion_link
=
not
None
,
expected_can_display_value
=
False
,
)
def
test_tabs_enrolled_or_staff
(
self
):
self
.
settings
.
FEATURES
[
'ENABLE_DISCUSSION_SERVICE'
]
=
True
for
is_enrolled
,
is_staff
in
[(
True
,
False
),
(
False
,
True
)]:
self
.
check_discussion
(
tab_list
=
self
.
tabs_with_discussion
,
expected_discussion_link
=
"default_discussion_link"
,
expected_can_display_value
=
True
,
is_enrolled
=
is_enrolled
,
is_staff
=
is_staff
)
def
test_tabs_not_enrolled_or_staff
(
self
):
self
.
settings
.
FEATURES
[
'ENABLE_DISCUSSION_SERVICE'
]
=
True
is_enrolled
=
is_staff
=
False
self
.
check_discussion
(
tab_list
=
self
.
tabs_with_discussion
,
expected_discussion_link
=
"default_discussion_link"
,
expected_can_display_value
=
False
,
is_enrolled
=
is_enrolled
,
is_staff
=
is_staff
)
lms/djangoapps/courseware/courses.py
View file @
81d8c40e
...
...
@@ -20,6 +20,7 @@ from xmodule.x_module import STUDENT_VIEW
from
courseware.access
import
has_access
from
courseware.model_data
import
FieldDataCache
from
courseware.module_render
import
get_module
from
student.models
import
CourseEnrollment
import
branding
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -72,7 +73,13 @@ def get_course_by_id(course_key, depth=0):
raise
Http404
(
"Course not found."
)
def
get_course_with_access
(
user
,
action
,
course_key
,
depth
=
0
):
class
UserNotEnrolled
(
Http404
):
def
__init__
(
self
,
course_key
):
super
(
UserNotEnrolled
,
self
)
.
__init__
()
self
.
course_key
=
course_key
def
get_course_with_access
(
user
,
action
,
course_key
,
depth
=
0
,
check_if_enrolled
=
False
):
"""
Given a course_key, look up the corresponding course descriptor,
check that the user has the access to perform the specified action
...
...
@@ -86,6 +93,11 @@ def get_course_with_access(user, action, course_key, depth=0):
course
=
get_course_by_id
(
course_key
,
depth
=
depth
)
if
not
has_access
(
user
,
action
,
course
,
course_key
):
if
check_if_enrolled
and
not
CourseEnrollment
.
is_enrolled
(
user
,
course_key
):
# If user is not enrolled, raise UserNotEnrolled exception that will
# be caught by middleware
raise
UserNotEnrolled
(
course_key
)
# Deliberately return a non-specific error message to avoid
# leaking info about access control settings
raise
Http404
(
"Course not found."
)
...
...
lms/djangoapps/courseware/middleware.py
0 → 100644
View file @
81d8c40e
"""
Middleware for the courseware app
"""
from
django.shortcuts
import
redirect
from
django.core.urlresolvers
import
reverse
from
courseware.courses
import
UserNotEnrolled
class
RedirectUnenrolledMiddleware
(
object
):
"""
Catch UserNotEnrolled errors thrown by `get_course_with_access` and redirect
users to the course about page
"""
def
process_exception
(
self
,
request
,
exception
):
if
isinstance
(
exception
,
UserNotEnrolled
):
course_key
=
exception
.
course_key
return
redirect
(
reverse
(
'courseware.views.course_about'
,
args
=
[
course_key
.
to_deprecated_string
()]
)
)
lms/djangoapps/courseware/tests/test_about.py
View file @
81d8c40e
...
...
@@ -46,6 +46,19 @@ class AboutTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
# Check that registration button is present
self
.
assertIn
(
REG_STR
,
resp
.
content
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_MKTG_SITE'
:
True
})
def
test_logged_in_marketing
(
self
):
self
.
setup_user
()
url
=
reverse
(
'about_course'
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()])
resp
=
self
.
client
.
get
(
url
)
# should be redirected
self
.
assertEqual
(
resp
.
status_code
,
302
)
# follow this time, and check we're redirected to the course info page
resp
=
self
.
client
.
get
(
url
,
follow
=
True
)
target_url
=
resp
.
redirect_chain
[
-
1
][
0
]
info_url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()])
self
.
assertTrue
(
target_url
.
endswith
(
info_url
))
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
AboutTestCaseXML
(
LoginEnrollmentTestCase
,
ModuleStoreTestCase
):
...
...
lms/djangoapps/courseware/tests/test_course_info.py
View file @
81d8c40e
...
...
@@ -20,12 +20,19 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
data
=
"OOGIE BLOOGIE"
,
display_name
=
"updates"
)
def
test_logged_in
(
self
):
def
test_logged_in
_unenrolled
(
self
):
self
.
setup_user
()
url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()])
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
"OOGIE BLOOGIE"
,
resp
.
content
)
self
.
assertIn
(
"You are not currently enrolled in this course"
,
resp
.
content
)
def
test_logged_in_enrolled
(
self
):
self
.
enroll
(
self
.
course
)
url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()])
resp
=
self
.
client
.
get
(
url
)
self
.
assertNotIn
(
"You are not currently enrolled in this course"
,
resp
.
content
)
def
test_anonymous_user
(
self
):
url
=
reverse
(
'info'
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()])
...
...
lms/djangoapps/courseware/tests/test_middleware.py
0 → 100644
View file @
81d8c40e
"""
Tests for courseware middleware
"""
from
django.core.urlresolvers
import
reverse
from
django.test.utils
import
override_settings
from
django.test.client
import
RequestFactory
from
django.http
import
Http404
from
mock
import
patch
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
import
courseware.courses
as
courses
from
courseware.middleware
import
RedirectUnenrolledMiddleware
from
xmodule.modulestore.tests.django_utils
import
ModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
CoursewareMiddlewareTestCase
(
ModuleStoreTestCase
):
"""Tests that courseware middleware is correctly redirected"""
def
setUp
(
self
):
self
.
course
=
CourseFactory
.
create
()
def
check_user_not_enrolled_redirect
(
self
):
"""A UserNotEnrolled exception should trigger a redirect"""
request
=
RequestFactory
()
.
get
(
"dummy_url"
)
response
=
RedirectUnenrolledMiddleware
()
.
process_exception
(
request
,
courses
.
UserNotEnrolled
(
self
.
course
.
id
)
)
self
.
assertEqual
(
response
.
status_code
,
302
)
# make sure we redirect to the course about page
expected_url
=
reverse
(
"about_course"
,
args
=
[
self
.
course
.
id
.
to_deprecated_string
()]
)
target_url
=
response
.
_headers
[
'location'
][
1
]
self
.
assertTrue
(
target_url
.
endswith
(
expected_url
))
def
test_user_not_enrolled_redirect
(
self
):
self
.
check_user_not_enrolled_redirect
()
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_MKTG_SITE"
:
True
})
def
test_user_not_enrolled_redirect_mktg
(
self
):
self
.
check_user_not_enrolled_redirect
()
def
test_process_404
(
self
):
"""A 404 should not trigger anything"""
request
=
RequestFactory
()
.
get
(
"dummy_url"
)
response
=
RedirectUnenrolledMiddleware
()
.
process_exception
(
request
,
Http404
()
)
self
.
assertIsNone
(
response
)
lms/djangoapps/courseware/tests/test_tabs.py
View file @
81d8c40e
...
...
@@ -95,4 +95,3 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase):
resp
=
self
.
client
.
get
(
url
)
self
.
assertEqual
(
resp
.
status_code
,
200
)
self
.
assertIn
(
self
.
xml_data
,
resp
.
content
)
lms/djangoapps/courseware/views.py
View file @
81d8c40e
...
...
@@ -19,7 +19,7 @@ from django.contrib.auth.decorators import login_required
from
django.views.decorators.http
import
require_GET
from
django.http
import
Http404
,
HttpResponse
from
django.shortcuts
import
redirect
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
,
marketing_link
from
django_future.csrf
import
ensure_csrf_cookie
from
django.views.decorators.cache
import
cache_control
from
django.db
import
transaction
...
...
@@ -569,6 +569,14 @@ def course_info(request, course_id):
reverifications
=
fetch_reverify_banner_info
(
request
,
course_key
)
studio_url
=
get_studio_url
(
course
,
'course_info'
)
# link to where the student should go to enroll in the course:
# about page if there is not marketing site, SITE_NAME if there is
url_to_enroll
=
reverse
(
course_about
,
args
=
[
course_id
])
if
settings
.
FEATURES
.
get
(
'ENABLE_MKTG_SITE'
):
url_to_enroll
=
marketing_link
(
'COURSES'
)
show_enroll_banner
=
request
.
user
.
is_authenticated
()
and
not
CourseEnrollment
.
is_enrolled
(
request
.
user
,
course
.
id
)
context
=
{
'request'
:
request
,
'course_id'
:
course_key
.
to_deprecated_string
(),
...
...
@@ -578,6 +586,8 @@ def course_info(request, course_id):
'masquerade'
:
masq
,
'studio_url'
:
studio_url
,
'reverifications'
:
reverifications
,
'show_enroll_banner'
:
show_enroll_banner
,
'url_to_enroll'
:
url_to_enroll
,
}
return
render_to_response
(
'courseware/info.html'
,
context
)
...
...
@@ -658,15 +668,15 @@ def course_about(request, course_id):
Assumes the course_id is in a valid format.
"""
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'see_exists'
,
course_key
)
if
microsite
.
get_value
(
'ENABLE_MKTG_SITE'
,
settings
.
FEATURES
.
get
(
'ENABLE_MKTG_SITE'
,
False
)
):
raise
Http404
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
return
redirect
(
reverse
(
'info'
,
args
=
[
course
.
id
.
to_deprecated_string
()]))
course
=
get_course_with_access
(
request
.
user
,
'see_exists'
,
course_key
)
registered
=
registered_for_course
(
course
,
request
.
user
)
staff_access
=
has_access
(
request
.
user
,
'staff'
,
course
)
studio_url
=
get_studio_url
(
course
,
'settings/details'
)
...
...
@@ -806,7 +816,7 @@ def _progress(request, course_key, student_id):
Course staff are allowed to see the progress of students in their class.
"""
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
depth
=
None
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
depth
=
None
,
check_if_enrolled
=
True
)
staff_access
=
has_access
(
request
.
user
,
'staff'
,
course
)
if
student_id
is
None
or
student_id
==
request
.
user
.
id
:
...
...
lms/djangoapps/django_comment_client/forum/tests.py
View file @
81d8c40e
...
...
@@ -20,6 +20,7 @@ from django_comment_client.tests.utils import CohortedContentTestCase
from
django_comment_client.forum
import
views
from
courseware.tests.modulestore_config
import
TEST_DATA_MIXED_MODULESTORE
from
courseware.courses
import
UserNotEnrolled
from
nose.tools
import
assert_true
# pylint: disable=E0611
from
mock
import
patch
,
Mock
,
ANY
,
call
...
...
@@ -913,3 +914,26 @@ class FollowedThreadsUnicodeTestCase(ModuleStoreTestCase, UnicodeTestMixin):
response_data
=
json
.
loads
(
response
.
content
)
self
.
assertEqual
(
response_data
[
"discussion_data"
][
0
][
"title"
],
text
)
self
.
assertEqual
(
response_data
[
"discussion_data"
][
0
][
"body"
],
text
)
@override_settings
(
MODULESTORE
=
TEST_DATA_MIXED_MODULESTORE
)
class
EnrollmentTestCase
(
ModuleStoreTestCase
):
"""
Tests for the behavior of views depending on if the student is enrolled
in the course
"""
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
def
setUp
(
self
):
super
(
EnrollmentTestCase
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
()
self
.
student
=
UserFactory
.
create
()
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
"ENABLE_DISCUSSION_SERVICE"
:
True
})
@patch
(
'lms.lib.comment_client.utils.requests.request'
)
def
test_unenrolled
(
self
,
mock_request
):
mock_request
.
side_effect
=
make_mock_request_impl
(
'dummy'
)
request
=
RequestFactory
()
.
get
(
'dummy_url'
)
request
.
user
=
self
.
student
with
self
.
assertRaises
(
UserNotEnrolled
):
views
.
forum_form_discussion
(
request
,
course_id
=
self
.
course
.
id
.
to_deprecated_string
())
lms/djangoapps/django_comment_client/forum/views.py
View file @
81d8c40e
...
...
@@ -163,7 +163,7 @@ def forum_form_discussion(request, course_id):
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
nr_transaction
=
newrelic
.
agent
.
current_transaction
()
course
=
get_course_with_access
(
request
.
user
,
'load_forum'
,
course_key
)
course
=
get_course_with_access
(
request
.
user
,
'load_forum'
,
course_key
,
check_if_enrolled
=
True
)
course_settings
=
make_course_settings
(
course
,
include_category_map
=
True
)
user
=
cc
.
User
.
from_django_user
(
request
.
user
)
...
...
lms/envs/common.py
View file @
81d8c40e
...
...
@@ -941,6 +941,9 @@ MIDDLEWARE_CLASSES = (
# use Django built in clickjacking protection
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
# to redirected unenrolled students to the course info page
'courseware.middleware.RedirectUnenrolledMiddleware'
,
'course_wiki.middleware.WikiAccessMiddleware'
,
)
...
...
lms/templates/courseware/course_navigation.html
View file @
81d8c40e
...
...
@@ -18,12 +18,16 @@ def url_class(is_active):
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%!
from
courseware
.
views
import
notification_image_for_tab
%
>
<
%!
from
student
.
models
import
CourseEnrollment
%
>
<
%
user_is_enrolled =
user.is_authenticated()
and
CourseEnrollment
.
is_enrolled
(
user
,
course
.
id
)
%
>
% if disable_tabs is UNDEFINED or not disable_tabs:
<nav
class=
"${active_page} course-material"
>
<div
class=
"inner-wrapper"
>
<ol
class=
"course-tabs"
>
% for tab in CourseTabList.iterate_displayable(course, settings, user.is_authenticated(), has_access(user, 'staff', course, course.id)):
% for tab in CourseTabList.iterate_displayable(course, settings, user.is_authenticated(), has_access(user, 'staff', course, course.id)
, user_is_enrolled
):
<
%
tab_is_active =
(tab.tab_id
==
active_page
)
or
(
tab
.
tab_id =
=
default_tab
)
tab_image =
notification_image_for_tab(tab,
user
,
course
)
...
...
lms/templates/courseware/info.html
View file @
81d8c40e
...
...
@@ -13,6 +13,24 @@
<
%
include
file=
"/dashboard/_dashboard_prompt_midcourse_reverify.html"
/>
% if show_enroll_banner:
<div
class=
"wrapper-msg urgency-low"
id=
"failed-verification-banner"
>
<div
class=
"msg msg-reverify is-dismissable"
>
<div
class=
"msg-content"
>
<h2
class=
"title"
>
${_("You are not enrolled yet")}
</h2>
<div
class=
"copy"
>
<p
class=
'enroll-message'
>
${_(u"You are not currently enrolled in this course. Sign up for it {link_start}here{link_end}!").format(
link_start=u"
<a
href=
{}
>
".format(url_to_enroll),
link_end=u"
</a>
"
)}
</p>
</div>
</div>
</div>
</div>
% endif
<
%
include
file=
"/courseware/course_navigation.html"
args=
"active_page='info'"
/>
<
%
block
name=
"js_extra"
>
...
...
@@ -36,7 +54,7 @@ $(document).ready(function(){
</div>
% endif
% endif
<h1>
${_("Course Updates
&
News")}
</h1>
${get_course_info_section(request, course, 'updates')}
</section>
...
...
lms/templates/help_modal.html
View file @
81d8c40e
...
...
@@ -37,7 +37,7 @@
<
%
discussion_tab =
CourseTabList.get_discussion(course)
if
course
else
None
discussion_link =
discussion_tab.link_func(course,
reverse
)
if
(
discussion_tab
and
discussion_tab
.
can_display
(
course
,
settings
,
True
,
True
))
else
None
discussion_link =
discussion_tab.link_func(course,
reverse
)
if
(
discussion_tab
and
discussion_tab
.
can_display
(
course
,
settings
,
True
,
True
,
True
))
else
None
%
>
% if discussion_link:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment