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
48e7fc81
Commit
48e7fc81
authored
May 03, 2016
by
attiyaishaque
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bokchoy Test Deleted.
parent
275a31ec
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
156 additions
and
603 deletions
+156
-603
common/test/acceptance/pages/lms/courseware.py
+0
-18
common/test/acceptance/pages/studio/index.py
+0
-22
common/test/acceptance/tests/studio/test_studio_home.py
+1
-81
lms/djangoapps/courseware/tests/test_views.py
+82
-41
lms/djangoapps/courseware/url_helpers.py
+5
-9
lms/djangoapps/courseware/views/index.py
+10
-0
lms/djangoapps/courseware/views/views.py
+28
-406
lms/templates/enroll_staff.html
+29
-25
lms/urls.py
+1
-1
No files found.
common/test/acceptance/pages/lms/courseware.py
View file @
48e7fc81
...
@@ -286,21 +286,3 @@ class CoursewareSequentialTabPage(CoursePage):
...
@@ -286,21 +286,3 @@ class CoursewareSequentialTabPage(CoursePage):
return the body of the sequential currently selected
return the body of the sequential currently selected
"""
"""
return
self
.
q
(
css
=
'#seq_content .xblock'
)
.
text
[
0
]
return
self
.
q
(
css
=
'#seq_content .xblock'
)
.
text
[
0
]
class
AboutPage
(
CoursePage
):
"""
Course about page.
"""
url_path
=
"about/"
def
is_browser_on_page
(
self
):
return
self
.
q
(
css
=
'.intro'
)
.
present
@property
def
is_register_button_present
(
self
):
"""
Returns True if the Enrollment button is visible on the about page.
"""
return
self
.
q
(
css
=
".register"
)
.
is_present
()
common/test/acceptance/pages/studio/index.py
View file @
48e7fc81
...
@@ -5,7 +5,6 @@ Studio Home page
...
@@ -5,7 +5,6 @@ Studio Home page
from
bok_choy.page_object
import
PageObject
from
bok_choy.page_object
import
PageObject
from
.
import
BASE_URL
from
.
import
BASE_URL
from
selenium.webdriver
import
ActionChains
from
selenium.webdriver
import
ActionChains
from
..common.utils
import
click_css
class
DashboardPage
(
PageObject
):
class
DashboardPage
(
PageObject
):
...
@@ -13,23 +12,11 @@ class DashboardPage(PageObject):
...
@@ -13,23 +12,11 @@ class DashboardPage(PageObject):
Studio Home page
Studio Home page
"""
"""
def
__init__
(
self
,
browser
):
"""
Initialize the page.
"""
super
(
DashboardPage
,
self
)
.
__init__
(
browser
)
url
=
BASE_URL
+
"/course/"
url
=
BASE_URL
+
"/course/"
def
is_browser_on_page
(
self
):
def
is_browser_on_page
(
self
):
return
self
.
q
(
css
=
'.content-primary'
)
.
visible
return
self
.
q
(
css
=
'.content-primary'
)
.
visible
def
mouse_hover
(
self
,
element
):
"""
Mouse over on given element.
"""
mouse_hover_action
=
ActionChains
(
self
.
browser
)
.
move_to_element
(
element
)
mouse_hover_action
.
perform
()
@property
@property
def
course_runs
(
self
):
def
course_runs
(
self
):
"""
"""
...
@@ -61,15 +48,6 @@ class DashboardPage(PageObject):
...
@@ -61,15 +48,6 @@ class DashboardPage(PageObject):
# Clicking on course with run will trigger an ajax event
# Clicking on course with run will trigger an ajax event
self
.
wait_for_ajax
()
self
.
wait_for_ajax
()
def
view_live
(
self
,
element
):
"""
Clicks the "View Live" link and switches to the new tab
"""
self
.
mouse_hover
(
self
.
browser
.
find_element_by_css_selector
(
'.course-item'
))
click_css
(
self
,
'.view-button'
,
require_notification
=
False
)
self
.
browser
.
switch_to_window
(
self
.
browser
.
window_handles
[
-
1
])
click_css
(
self
,
element
,
require_notification
=
False
)
def
has_new_library_button
(
self
):
def
has_new_library_button
(
self
):
"""
"""
(bool) is the "New Library" button present?
(bool) is the "New Library" button present?
...
...
common/test/acceptance/tests/studio/test_studio_home.py
View file @
48e7fc81
"""
"""
Acceptance tests for Home Page (My Courses / My Libraries).
Acceptance tests for Home Page (My Courses / My Libraries).
"""
"""
import
os
import
uuid
from
bok_choy.web_app_test
import
WebAppTest
from
bok_choy.web_app_test
import
WebAppTest
from
common.test.acceptance.pages.common.logout
import
LogoutPage
from
common.test.acceptance.pages.lms.courseware
import
AboutPage
,
CoursewarePage
from
flaky
import
flaky
from
flaky
import
flaky
from
opaque_keys.edx.locator
import
LibraryLocator
,
CourseLocator
from
opaque_keys.edx.locator
import
LibraryLocator
from
uuid
import
uuid4
from
uuid
import
uuid4
from
...fixtures
import
PROGRAMS_STUB_URL
from
...fixtures
import
PROGRAMS_STUB_URL
...
@@ -178,78 +173,3 @@ class StudioLanguageTest(WebAppTest):
...
@@ -178,78 +173,3 @@ class StudioLanguageTest(WebAppTest):
get_selected_option_text
(
language_selector
),
get_selected_option_text
(
language_selector
),
u'Dummy Language (Esperanto)'
u'Dummy Language (Esperanto)'
)
)
class
CourseNotEnrollTest
(
WebAppTest
):
"""
Test that we can create a new content library on the studio home page.
"""
def
setUp
(
self
):
"""
Load the helper for the home page (dashboard page)
"""
super
(
CourseNotEnrollTest
,
self
)
.
setUp
()
self
.
auth_page
=
AutoAuthPage
(
self
.
browser
,
staff
=
True
)
self
.
dashboard_page
=
DashboardPage
(
self
.
browser
)
self
.
course_name
=
"New Course Name"
self
.
course_org
=
"orgX"
self
.
course_number
=
str
(
uuid
.
uuid4
()
.
get_hex
()
.
upper
()[
0
:
6
])
self
.
course_run
=
"2015_T2"
def
course_id
(
self
):
"""
Returns the serialized course_key for the test
"""
# TODO - is there a better way to make this agnostic to the underlying default module store?
default_store
=
os
.
environ
.
get
(
'DEFAULT_STORE'
,
'split'
)
course_key
=
CourseLocator
(
self
.
course_org
,
self
.
course_number
,
self
.
course_run
,
deprecated
=
(
default_store
==
'split'
)
)
return
unicode
(
course_key
)
def
test_unenroll_course
(
self
):
"""
From the home page:
Click "New Course" ,Fill out the form
Submit the form
Return to the home page and logout
Login with the staff user which is not enrolled in the course
click the view live button of the course
Here are two scenario:
-First click the Don't Enroll button
-Second click the Enroll button and see the response.
"""
self
.
auth_page
.
visit
()
self
.
dashboard_page
.
visit
()
self
.
assertTrue
(
self
.
dashboard_page
.
new_course_button
.
present
)
self
.
dashboard_page
.
click_new_course_button
()
self
.
assertTrue
(
self
.
dashboard_page
.
is_new_course_form_visible
())
self
.
dashboard_page
.
fill_new_course_form
(
self
.
course_name
,
self
.
course_org
,
self
.
course_number
,
self
.
course_run
)
self
.
assertTrue
(
self
.
dashboard_page
.
is_new_course_form_valid
())
self
.
dashboard_page
.
submit_new_course_form
()
self
.
dashboard_page
.
visit
()
LogoutPage
(
self
.
browser
)
.
visit
()
AutoAuthPage
(
self
.
browser
,
course_id
=
None
,
staff
=
True
)
.
visit
()
self
.
dashboard_page
.
visit
()
self
.
dashboard_page
.
view_live
(
'input[name= "dont_enroll"]'
)
about_page
=
AboutPage
(
self
.
browser
,
self
.
course_id
)
about_page
.
wait_for_page
()
self
.
assertTrue
(
about_page
.
is_browser_on_page
())
self
.
assertTrue
(
about_page
.
is_register_button_present
)
self
.
dashboard_page
.
visit
()
self
.
dashboard_page
.
view_live
(
'input[name= "enroll"]'
)
course_ware
=
CoursewarePage
(
self
.
browser
,
self
.
course_id
)
course_ware
.
wait_for_page
()
self
.
assertTrue
(
course_ware
.
is_browser_on_page
())
lms/djangoapps/courseware/tests/test_views.py
View file @
48e7fc81
...
@@ -39,7 +39,7 @@ from course_modes.tests.factories import CourseModeFactory
...
@@ -39,7 +39,7 @@ from course_modes.tests.factories import CourseModeFactory
from
courseware.model_data
import
set_score
from
courseware.model_data
import
set_score
from
courseware.module_render
import
toc_for_course
from
courseware.module_render
import
toc_for_course
from
courseware.testutils
import
RenderXBlockTestMixin
from
courseware.testutils
import
RenderXBlockTestMixin
from
courseware.tests.factories
import
StudentModuleFactory
from
courseware.tests.factories
import
StudentModuleFactory
,
GlobalStaffFactory
from
courseware.url_helpers
import
get_redirect_url
from
courseware.url_helpers
import
get_redirect_url
from
courseware.user_state_client
import
DjangoXBlockUserStateClient
from
courseware.user_state_client
import
DjangoXBlockUserStateClient
from
courseware.views.index
import
render_accordion
,
CoursewareIndex
from
courseware.views.index
import
render_accordion
,
CoursewareIndex
...
@@ -196,7 +196,7 @@ class ViewsTestCase(ModuleStoreTestCase):
...
@@ -196,7 +196,7 @@ class ViewsTestCase(ModuleStoreTestCase):
def
setUp
(
self
):
def
setUp
(
self
):
super
(
ViewsTestCase
,
self
)
.
setUp
()
super
(
ViewsTestCase
,
self
)
.
setUp
()
self
.
course
=
CourseFactory
.
create
(
display_name
=
u'teꜱᴛ course'
)
self
.
course
=
CourseFactory
.
create
(
display_name
=
u'teꜱᴛ course'
,
run
=
"Testing_course"
)
self
.
chapter
=
ItemFactory
.
create
(
self
.
chapter
=
ItemFactory
.
create
(
category
=
'chapter'
,
category
=
'chapter'
,
parent_location
=
self
.
course
.
location
,
parent_location
=
self
.
course
.
location
,
...
@@ -323,63 +323,104 @@ class ViewsTestCase(ModuleStoreTestCase):
...
@@ -323,63 +323,104 @@ class ViewsTestCase(ModuleStoreTestCase):
self
.
assertNotIn
(
'Problem 1'
,
response
.
content
)
self
.
assertNotIn
(
'Problem 1'
,
response
.
content
)
self
.
assertNotIn
(
'Problem 2'
,
response
.
content
)
self
.
assertNotIn
(
'Problem 2'
,
response
.
content
)
def
_create_
url_for_enroll_staff
(
self
):
def
_create_
global_staff_user
(
self
):
"""
"""
User will have satff access and creates the url for enroll_staff view
Create global staff user and log them in
"""
"""
self
.
user
.
is_staff
=
True
self
.
global_staff
=
GlobalStaffFactory
.
create
()
# pylint: disable=attribute-defined-outside-init
self
.
user
.
save
()
# pylint: disable=no-member
self
.
client
.
login
(
username
=
self
.
global_staff
.
username
,
password
=
'test'
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
self
.
password
)
# create the course
course
=
CourseFactory
.
create
()
def
_create_url_for_enroll_staff
(
self
):
"""
creates the courseware url and enroll staff url
"""
# create the _next parameter
# create the _next parameter
courseware_url
=
reverse
(
'courseware'
,
kwargs
=
{
courseware_url
=
reverse
(
'course_id'
:
unicode
(
course
.
id
)})
+
'?activate_block_id=test_block_id'
'courseware_section'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course_key
),
'chapter'
:
unicode
(
self
.
chapter
.
location
.
name
),
'section'
:
unicode
(
self
.
section
.
location
.
name
),
}
)
# create the url for enroll_staff view
# create the url for enroll_staff view
enroll_
staff_url
=
"{enroll_staff
_url}?next={courseware_url}"
.
format
(
enroll_
url
=
"{enroll
_url}?next={courseware_url}"
.
format
(
enroll_
staff_url
=
reverse
(
'enroll_staff'
,
kwargs
=
{
'course_id'
:
unicode
(
course
.
id
)}),
enroll_
url
=
reverse
(
'enroll_staff'
,
kwargs
=
{
'course_id'
:
unicode
(
self
.
course
.
id
)}),
courseware_url
=
courseware_url
courseware_url
=
courseware_url
)
)
return
enroll_staff_url
,
course
.
id
return
courseware_url
,
enroll_url
def
test_redirection_unenrolled_staff
(
self
):
@ddt.data
(
({
'enroll'
:
"Enroll"
},
True
),
({
'dont_enroll'
:
"Don't enroll"
},
False
))
@ddt.unpack
def
test_enroll_staff_redirection
(
self
,
data
,
enrollment
):
"""
"""
Test that staff is not redirected to the 'about' page when visiting an unregistered course
Verify unenrolled staff is redirected to correct url.
"""
"""
enroll_staff_url
,
__
=
self
.
_create_url_for_enroll_staff
()
self
.
_create_global_staff_user
()
courseware_url
,
enroll_url
=
self
.
_create_url_for_enroll_staff
()
# Check the GET method
response
=
self
.
client
.
post
(
enroll_url
,
data
=
data
,
follow
=
True
)
response
=
self
.
client
.
get
(
enroll_staff_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_content
=
response
.
content
self
.
assertIn
(
'Enroll'
,
response_content
)
self
.
assertIn
(
"dont_enroll"
,
response_content
)
@ddt.data
(
# we were redirected to our current location
({
'enroll'
:
"Enroll"
},
'courses/{}/courseware?activate_block_id=test_block_id'
),
self
.
assertIn
(
302
,
response
.
redirect_chain
[
0
])
({
'dont_enroll'
:
"Don't enroll"
},
'/courses/{}/about'
))
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
1
)
@ddt.unpack
if
enrollment
:
def
test_enroll_staff_redirection
(
self
,
data
,
expected_url
):
self
.
assertRedirects
(
response
,
courseware_url
)
else
:
self
.
assertRedirects
(
response
,
'/courses/{}/about'
.
format
(
unicode
(
self
.
course_key
)))
def
test_enroll_staff_with_invalid_data
(
self
):
"""
"""
Verify unenrolled staff is redirected to the page according to data passed.
If we try to post with an invalid data pattern, then we'll redirected to
course about page.
"""
"""
enroll_staff_url
,
course_id
=
self
.
_create_url_for_enroll_staff
()
self
.
_create_global_staff_user
()
response
=
self
.
client
.
post
(
enroll_staff_url
,
data
=
data
)
__
,
enroll_url
=
self
.
_create_url_for_enroll_staff
()
response
=
self
.
client
.
post
(
enroll_url
,
data
=
{
'test'
:
"test"
})
# Here we check the status code 302 because of the redirect
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertRedirects
(
response
,
expected_url
.
format
(
unicode
(
course_id
)))
self
.
assertRedirects
(
response
,
'/courses/{}/about'
.
format
(
unicode
(
self
.
course_key
)))
def
test_
enroll_staff_redirection_invalid_data
(
self
):
def
test_
courseware_redirection
(
self
):
"""
"""
Verify unenrolled staff is redirected to the page according to data passed.
Tests that a global staff member is redirected to the staff enrollment page.
Un-enrolled Staff user should be redirected to the staff enrollment page accessing courseware,
user chooses to enroll in the course. User is enrolled and redirected to the requested url.
Scenario:
1. Un-enrolled staff tries to access any course vertical (courseware url).
2. User is redirected to the staff enrollment page.
3. User chooses to enroll in the course.
4. User is enrolled in the course and redirected to the requested courseware url.
"""
"""
enroll_staff_url
,
__
=
self
.
_create_url_for_enroll_staff
()
self
.
_create_global_staff_user
()
response
=
self
.
client
.
post
(
enroll_staff_url
,
data
=
{
'test'
:
"test"
})
courseware_url
,
enroll_url
=
self
.
_create_url_for_enroll_staff
()
self
.
assertEqual
(
response
.
status_code
,
404
)
# Accessing the courseware url in which not enrolled & redirected to staff enrollment page
response
=
self
.
client
.
get
(
courseware_url
,
follow
=
True
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertIn
(
302
,
response
.
redirect_chain
[
0
])
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
1
)
self
.
assertRedirects
(
response
,
enroll_url
)
# Accessing the enroll staff url and verify the correct url
response
=
self
.
client
.
get
(
enroll_url
)
self
.
assertEqual
(
response
.
status_code
,
200
)
response_content
=
response
.
content
self
.
assertIn
(
'Enroll'
,
response_content
)
self
.
assertIn
(
"dont_enroll"
,
response_content
)
# Post the valid data to enroll the staff in the course
response
=
self
.
client
.
post
(
enroll_url
,
data
=
{
'enroll'
:
"Enroll"
},
follow
=
True
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertIn
(
302
,
response
.
redirect_chain
[
0
])
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
1
)
self
.
assertRedirects
(
response
,
courseware_url
)
# Verify staff has been enrolled to the given course
self
.
assertTrue
(
CourseEnrollment
.
is_enrolled
(
self
.
global_staff
,
self
.
course
.
id
))
@unittest.skipUnless
(
settings
.
FEATURES
.
get
(
'ENABLE_SHOPPING_CART'
),
"Shopping Cart not enabled in settings"
)
@unittest.skipUnless
(
settings
.
FEATURES
.
get
(
'ENABLE_SHOPPING_CART'
),
"Shopping Cart not enabled in settings"
)
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_PAID_COURSE_REGISTRATION'
:
True
})
@patch.dict
(
settings
.
FEATURES
,
{
'ENABLE_PAID_COURSE_REGISTRATION'
:
True
})
...
...
lms/djangoapps/courseware/url_helpers.py
View file @
48e7fc81
...
@@ -42,27 +42,23 @@ def get_redirect_url(course_key, usage_key):
...
@@ -42,27 +42,23 @@ def get_redirect_url(course_key, usage_key):
# Here we use the navigation_index from the position returned from
# Here we use the navigation_index from the position returned from
# path_to_location - we can only navigate to the topmost vertical at the
# path_to_location - we can only navigate to the topmost vertical at the
# moment
# moment
redirect_url
=
reverse
(
redirect_url
=
reverse
(
'courseware_position'
,
'courseware_position'
,
args
=
(
unicode
(
course_key
),
chapter
,
section
,
navigation_index
(
position
))
args
=
(
unicode
(
course_key
),
chapter
,
section
,
navigation_index
(
position
))
)
)
redirect_url
+=
"?{}"
.
format
(
urlencode
({
'activate_block_id'
:
unicode
(
final_target_id
)}))
redirect_url
+=
"?{}"
.
format
(
urlencode
({
'activate_block_id'
:
unicode
(
final_target_id
)}))
return
redirect_url
return
redirect_url
def
get_redirect_url_for_global_staff
(
course_key
,
location
):
def
get_redirect_url_for_global_staff
(
course_key
,
_next
):
"""
"""
Returns the redirect url
Returns the redirect url
for staff enrollment
Args:
Args:
course_key(str): Course key string
course_key(str): Course key string
location(str): The location id
of course component
_next(str): Redirect url
of course component
"""
"""
redirect_url
=
(
"{url}?next={redirect}"
.
format
(
_next
=
get_redirect_url
(
course_key
,
location
)
redirect_url
=
"{url}?next={redirect}"
.
format
(
url
=
reverse
(
'enroll_staff'
,
args
=
[
unicode
(
course_key
)]),
url
=
reverse
(
'enroll_staff'
,
args
=
[
unicode
(
course_key
)]),
redirect
=
_next
)
redirect
=
_next
)
)
return
redirect_url
return
redirect_url
lms/djangoapps/courseware/views/index.py
View file @
48e7fc81
...
@@ -15,6 +15,8 @@ from django.views.decorators.cache import cache_control
...
@@ -15,6 +15,8 @@ from django.views.decorators.cache import cache_control
from
django.views.decorators.csrf
import
ensure_csrf_cookie
from
django.views.decorators.csrf
import
ensure_csrf_cookie
from
django.views.generic
import
View
from
django.views.generic
import
View
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
courseware.url_helpers
import
get_redirect_url_for_global_staff
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
from
edxmako.shortcuts
import
render_to_response
,
render_to_string
import
logging
import
logging
import
newrelic.agent
import
newrelic.agent
...
@@ -26,7 +28,9 @@ from opaque_keys.edx.keys import CourseKey
...
@@ -26,7 +28,9 @@ from opaque_keys.edx.keys import CourseKey
from
openedx.core.lib.gating
import
api
as
gating_api
from
openedx.core.lib.gating
import
api
as
gating_api
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preference
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preference
from
shoppingcart.models
import
CourseRegistrationCode
from
shoppingcart.models
import
CourseRegistrationCode
from
student.models
import
CourseEnrollment
from
student.views
import
is_course_blocked
from
student.views
import
is_course_blocked
from
student.roles
import
GlobalStaff
from
util.views
import
ensure_valid_course_key
from
util.views
import
ensure_valid_course_key
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore.django
import
modulestore
from
xmodule.x_module
import
STUDENT_VIEW
from
xmodule.x_module
import
STUDENT_VIEW
...
@@ -89,6 +93,7 @@ class CoursewareIndex(View):
...
@@ -89,6 +93,7 @@ class CoursewareIndex(View):
self
.
section_url_name
=
section
self
.
section_url_name
=
section
self
.
position
=
position
self
.
position
=
position
self
.
chapter
,
self
.
section
=
None
,
None
self
.
chapter
,
self
.
section
=
None
,
None
self
.
url
=
request
.
path
try
:
try
:
self
.
_init_new_relic
()
self
.
_init_new_relic
()
...
@@ -221,6 +226,11 @@ class CoursewareIndex(View):
...
@@ -221,6 +226,11 @@ class CoursewareIndex(View):
self
.
effective_user
,
self
.
effective_user
,
unicode
(
self
.
course
.
id
)
unicode
(
self
.
course
.
id
)
)
)
user_is_global_staff
=
GlobalStaff
()
.
has_user
(
self
.
effective_user
)
user_is_enrolled
=
CourseEnrollment
.
is_enrolled
(
self
.
effective_user
,
self
.
course_key
)
if
user_is_global_staff
and
not
user_is_enrolled
:
redirect_url
=
get_redirect_url_for_global_staff
(
self
.
course_key
,
_next
=
self
.
url
)
raise
Redirect
(
redirect_url
)
raise
Redirect
(
reverse
(
'about_course'
,
args
=
[
unicode
(
self
.
course
.
id
)]))
raise
Redirect
(
reverse
(
'about_course'
,
args
=
[
unicode
(
self
.
course
.
id
)]))
def
_redirect_if_needed_for_prereqs
(
self
):
def
_redirect_if_needed_for_prereqs
(
self
):
...
...
lms/djangoapps/courseware/views/views.py
View file @
48e7fc81
...
@@ -14,6 +14,7 @@ from django.contrib.auth.decorators import login_required
...
@@ -14,6 +14,7 @@ from django.contrib.auth.decorators import login_required
from
django.contrib.auth.models
import
User
,
AnonymousUser
from
django.contrib.auth.models
import
User
,
AnonymousUser
from
django.core.exceptions
import
PermissionDenied
from
django.core.exceptions
import
PermissionDenied
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.core.context_processors
import
csrf
from
django.db
import
transaction
from
django.db
import
transaction
from
django.db.models
import
Q
from
django.db.models
import
Q
from
django.http
import
Http404
,
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
from
django.http
import
Http404
,
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
...
@@ -32,7 +33,6 @@ from opaque_keys import InvalidKeyError
...
@@ -32,7 +33,6 @@ from opaque_keys import InvalidKeyError
from
opaque_keys.edx.keys
import
CourseKey
,
UsageKey
from
opaque_keys.edx.keys
import
CourseKey
,
UsageKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
rest_framework
import
status
from
rest_framework
import
status
from
xblock.fragment
import
Fragment
from
instructor.views.api
import
require_global_staff
from
instructor.views.api
import
require_global_staff
import
shoppingcart
import
shoppingcart
...
@@ -41,6 +41,7 @@ import survey.views
...
@@ -41,6 +41,7 @@ import survey.views
from
certificates
import
api
as
certs_api
from
certificates
import
api
as
certs_api
from
openedx.core.djangoapps.models.course_details
import
CourseDetails
from
openedx.core.djangoapps.models.course_details
import
CourseDetails
from
commerce.utils
import
EcommerceService
from
commerce.utils
import
EcommerceService
from
enrollment.api
import
add_enrollment
from
course_modes.models
import
CourseMode
from
course_modes.models
import
CourseMode
from
courseware
import
grades
from
courseware
import
grades
from
courseware.access
import
has_access
,
has_ccx_coach_role
,
_adjust_start_date_for_beta_testers
from
courseware.access
import
has_access
,
has_ccx_coach_role
,
_adjust_start_date_for_beta_testers
...
@@ -76,12 +77,8 @@ from openedx.core.djangoapps.theming import helpers as theming_helpers
...
@@ -76,12 +77,8 @@ from openedx.core.djangoapps.theming import helpers as theming_helpers
from
shoppingcart.utils
import
is_shopping_cart_enabled
from
shoppingcart.utils
import
is_shopping_cart_enabled
from
openedx.core.djangoapps.self_paced.models
import
SelfPacedConfiguration
from
openedx.core.djangoapps.self_paced.models
import
SelfPacedConfiguration
from
student.models
import
UserTestGroup
,
CourseEnrollment
from
student.models
import
UserTestGroup
,
CourseEnrollment
from
student.roles
import
GlobalStaff
from
student.roles
import
GlobalStaff
from
student.views
import
is_course_blocked
from
util.cache
import
cache
,
cache_if_anonymous
from
util.cache
import
cache
,
cache_if_anonymous
from
util.course_key_utils
import
from_string_or_404
from
util.date_utils
import
strftime_localized
from
util.date_utils
import
strftime_localized
from
util.db
import
outer_atomic
from
util.db
import
outer_atomic
from
util.milestones_helpers
import
get_prerequisite_courses_display
from
util.milestones_helpers
import
get_prerequisite_courses_display
...
@@ -204,386 +201,6 @@ def get_current_child(xmodule, min_depth=None, requested_child=None):
...
@@ -204,386 +201,6 @@ def get_current_child(xmodule, min_depth=None, requested_child=None):
return
child
return
child
def
redirect_to_course_position
(
course_module
,
content_depth
):
"""
Return a redirect to the user's current place in the course.
If this is the user's first time, redirects to COURSE/CHAPTER/SECTION.
If this isn't the users's first time, redirects to COURSE/CHAPTER,
and the view will find the current section and display a message
about reusing the stored position.
If there is no current position in the course or chapter, then selects
the first child.
"""
urlargs
=
{
'course_id'
:
course_module
.
id
.
to_deprecated_string
()}
chapter
=
get_current_child
(
course_module
,
min_depth
=
content_depth
)
if
chapter
is
None
:
# oops. Something bad has happened.
raise
Http404
(
"No chapter found when loading current position in course"
)
urlargs
[
'chapter'
]
=
chapter
.
url_name
if
course_module
.
position
is
not
None
:
return
redirect
(
reverse
(
'courseware_chapter'
,
kwargs
=
urlargs
))
# Relying on default of returning first child
section
=
get_current_child
(
chapter
,
min_depth
=
content_depth
-
1
)
if
section
is
None
:
raise
Http404
(
"No section found when loading current position in course"
)
urlargs
[
'section'
]
=
section
.
url_name
return
redirect
(
reverse
(
'courseware_section'
,
kwargs
=
urlargs
))
def
save_child_position
(
seq_module
,
child_name
):
"""
child_name: url_name of the child
"""
for
position
,
c
in
enumerate
(
seq_module
.
get_display_items
(),
start
=
1
):
if
c
.
location
.
name
==
child_name
:
# Only save if position changed
if
position
!=
seq_module
.
position
:
seq_module
.
position
=
position
# Save this new position to the underlying KeyValueStore
seq_module
.
save
()
def
save_positions_recursively_up
(
user
,
request
,
field_data_cache
,
xmodule
,
course
=
None
):
"""
Recurses up the course tree starting from a leaf
Saving the position property based on the previous node as it goes
"""
current_module
=
xmodule
while
current_module
:
parent_location
=
modulestore
()
.
get_parent_location
(
current_module
.
location
)
parent
=
None
if
parent_location
:
parent_descriptor
=
modulestore
()
.
get_item
(
parent_location
)
parent
=
get_module_for_descriptor
(
user
,
request
,
parent_descriptor
,
field_data_cache
,
current_module
.
location
.
course_key
,
course
=
course
)
if
parent
and
hasattr
(
parent
,
'position'
):
save_child_position
(
parent
,
current_module
.
location
.
name
)
current_module
=
parent
@transaction.non_atomic_requests
@login_required
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
@ensure_valid_course_key
@outer_atomic
(
read_committed
=
True
)
def
index
(
request
,
course_id
,
chapter
=
None
,
section
=
None
,
position
=
None
):
"""
Displays courseware accordion and associated content. If course, chapter,
and section are all specified, renders the page, or returns an error if they
are invalid.
If section is not specified, displays the accordion opened to the right chapter.
If neither chapter or section are specified, redirects to user's most recent
chapter, or the first chapter if this is the user's first visit.
Arguments:
- request : HTTP request
- course_id : course id (str: ORG/course/URL_NAME)
- chapter : chapter url_name (str)
- section : section url_name (str)
- position : position in module, eg of <sequential> module (str)
Returns:
- HTTPresponse
"""
course_key
=
CourseKey
.
from_string
(
course_id
)
# Gather metrics for New Relic so we can slice data in New Relic Insights
newrelic
.
agent
.
add_custom_parameter
(
'course_id'
,
unicode
(
course_key
))
newrelic
.
agent
.
add_custom_parameter
(
'org'
,
unicode
(
course_key
.
org
))
user
=
User
.
objects
.
prefetch_related
(
"groups"
)
.
get
(
id
=
request
.
user
.
id
)
redeemed_registration_codes
=
CourseRegistrationCode
.
objects
.
filter
(
course_id
=
course_key
,
registrationcoderedemption__redeemed_by
=
request
.
user
)
# Redirect to dashboard if the course is blocked due to non-payment.
if
is_course_blocked
(
request
,
redeemed_registration_codes
,
course_key
):
# registration codes may be generated via Bulk Purchase Scenario
# we have to check only for the invoice generated registration codes
# that their invoice is valid or not
log
.
warning
(
u'User
%
s cannot access the course
%
s because payment has not yet been received'
,
user
,
course_key
.
to_deprecated_string
()
)
return
redirect
(
reverse
(
'dashboard'
))
request
.
user
=
user
# keep just one instance of User
with
modulestore
()
.
bulk_operations
(
course_key
):
return
_index_bulk_op
(
request
,
course_key
,
chapter
,
section
,
position
)
# pylint: disable=too-many-statements
def
_index_bulk_op
(
request
,
course_key
,
chapter
,
section
,
position
):
"""
Render the index page for the specified course.
"""
# Verify that position a string is in fact an int
if
position
is
not
None
:
try
:
int
(
position
)
except
ValueError
:
raise
Http404
(
u"Position {} is not an integer!"
.
format
(
position
))
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_key
,
depth
=
2
)
staff_access
=
has_access
(
request
.
user
,
'staff'
,
course
)
masquerade
,
user
=
setup_masquerade
(
request
,
course_key
,
staff_access
,
reset_masquerade_data
=
True
)
registered
=
registered_for_course
(
course
,
user
)
if
not
registered
:
# TODO (vshnayder): do course instructors need to be registered to see course?
log
.
debug
(
u'User
%
s tried to view course
%
s but is not enrolled'
,
user
,
course
.
location
.
to_deprecated_string
())
if
GlobalStaff
()
.
has_user
(
user
):
redirect_url
=
get_redirect_url_for_global_staff
(
course_key
,
course
.
location
)
return
redirect
(
redirect_url
)
return
redirect
(
reverse
(
'about_course'
,
args
=
[
unicode
(
course_key
)]))
# see if all pre-requisites (as per the milestones app feature) have been fulfilled
# Note that if the pre-requisite feature flag has been turned off (default) then this check will
# always pass
if
not
has_access
(
user
,
'view_courseware_with_prerequisites'
,
course
):
# prerequisites have not been fulfilled therefore redirect to the Dashboard
log
.
info
(
u'User
%
d tried to view course
%
s '
u'without fulfilling prerequisites'
,
user
.
id
,
unicode
(
course
.
id
))
return
redirect
(
reverse
(
'dashboard'
))
# Entrance Exam Check
# If the course has an entrance exam and the requested chapter is NOT the entrance exam, and
# the user hasn't yet met the criteria to bypass the entrance exam, redirect them to the exam.
if
chapter
and
course_has_entrance_exam
(
course
):
chapter_descriptor
=
course
.
get_child_by
(
lambda
m
:
m
.
location
.
name
==
chapter
)
if
chapter_descriptor
and
not
getattr
(
chapter_descriptor
,
'is_entrance_exam'
,
False
)
\
and
user_must_complete_entrance_exam
(
request
,
user
,
course
):
log
.
info
(
u'User
%
d tried to view course
%
s without passing entrance exam'
,
user
.
id
,
unicode
(
course
.
id
))
return
redirect
(
reverse
(
'courseware'
,
args
=
[
unicode
(
course
.
id
)]))
# Gated Content Check
gated_content
=
gating_api
.
get_gated_content
(
course
,
user
)
if
section
and
gated_content
:
for
usage_key
in
gated_content
:
if
section
in
usage_key
:
raise
Http404
# check to see if there is a required survey that must be taken before
# the user can access the course.
if
survey
.
utils
.
must_answer_survey
(
course
,
user
):
return
redirect
(
reverse
(
'course_survey'
,
args
=
[
unicode
(
course
.
id
)]))
bookmarks_api_url
=
reverse
(
'bookmarks'
)
try
:
field_data_cache
=
FieldDataCache
.
cache_for_descriptor_descendents
(
course_key
,
user
,
course
,
depth
=
2
)
studio_url
=
get_studio_url
(
course
,
'course'
)
language_preference
=
get_user_preference
(
request
.
user
,
LANGUAGE_KEY
)
if
not
language_preference
:
language_preference
=
settings
.
LANGUAGE_CODE
context
=
{
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'COURSE_TITLE'
:
course
.
display_name_with_default_escaped
,
'course'
:
course
,
'init'
:
''
,
'fragment'
:
Fragment
(),
'staff_access'
:
staff_access
,
'studio_url'
:
studio_url
,
'masquerade'
:
masquerade
,
'xqa_server'
:
settings
.
FEATURES
.
get
(
'XQA_SERVER'
,
"http://your_xqa_server.com"
),
'bookmarks_api_url'
:
bookmarks_api_url
,
'language_preference'
:
language_preference
,
'disable_optimizely'
:
True
,
}
table_of_contents
,
__
,
__
=
toc_for_course
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
[
'accordion'
]
=
render_accordion
(
request
,
course
,
table_of_contents
)
now
=
datetime
.
now
(
UTC
())
effective_start
=
_adjust_start_date_for_beta_testers
(
user
,
course
,
course_key
)
if
not
in_preview_mode
()
and
staff_access
and
now
<
effective_start
:
# Disable student view button if user is staff and
# course is not yet visible to students.
context
[
'disable_student_access'
]
=
True
has_content
=
course
.
has_children_at_depth
(
CONTENT_DEPTH
)
if
not
has_content
:
# Show empty courseware for a course with no units
return
render_to_response
(
'courseware/courseware.html'
,
context
)
elif
chapter
is
None
:
# Check first to see if we should instead redirect the user to an Entrance Exam
if
course_has_entrance_exam
(
course
):
exam_chapter
=
get_entrance_exam_content
(
request
,
course
)
if
exam_chapter
:
if
exam_chapter
.
get_children
():
exam_section
=
exam_chapter
.
get_children
()[
0
]
if
exam_section
:
return
redirect
(
'courseware_section'
,
course_id
=
unicode
(
course_key
),
chapter
=
exam_chapter
.
url_name
,
section
=
exam_section
.
url_name
)
# passing CONTENT_DEPTH avoids returning 404 for a course with an
# empty first section and a second section with content
return
redirect_to_course_position
(
course
,
CONTENT_DEPTH
)
chapter_descriptor
=
course
.
get_child_by
(
lambda
m
:
m
.
location
.
name
==
chapter
)
if
chapter_descriptor
is
not
None
:
save_child_position
(
course
,
chapter
)
else
:
# User may be trying to access a chapter that isn't live yet
if
masquerade
and
masquerade
.
role
==
'student'
:
# if staff is masquerading as student be kinder, don't 404
log
.
debug
(
'staff masquerading as student: no chapter
%
s'
,
chapter
)
return
redirect
(
reverse
(
'courseware'
,
args
=
[
course
.
id
.
to_deprecated_string
()]))
raise
Http404
(
'No chapter descriptor found with name {}'
.
format
(
chapter
))
if
course_has_entrance_exam
(
course
):
# Message should not appear outside the context of entrance exam subsection.
# if section is none then we don't need to show message on welcome back screen also.
if
getattr
(
chapter_descriptor
,
'is_entrance_exam'
,
False
)
and
section
is
not
None
:
context
[
'entrance_exam_current_score'
]
=
get_entrance_exam_score
(
request
,
course
)
context
[
'entrance_exam_passed'
]
=
user_has_passed_entrance_exam
(
request
,
course
)
if
section
is
None
:
section_descriptor
=
get_current_child
(
chapter_descriptor
,
requested_child
=
request
.
GET
.
get
(
"child"
))
if
section_descriptor
:
section
=
section_descriptor
.
url_name
else
:
# Something went wrong -- perhaps this chapter has no sections visible to the user.
# Clearing out the last-visited state and showing "first-time" view by redirecting
# to courseware.
course
.
position
=
None
course
.
save
()
return
redirect
(
reverse
(
'courseware'
,
args
=
[
course
.
id
.
to_deprecated_string
()]))
else
:
section_descriptor
=
chapter_descriptor
.
get_child_by
(
lambda
m
:
m
.
location
.
name
==
section
)
if
section_descriptor
is
None
:
# Specifically asked-for section doesn't exist
if
masquerade
and
masquerade
.
role
==
'student'
:
# don't 404 if staff is masquerading as student
log
.
debug
(
'staff masquerading as student: no section
%
s'
,
section
)
return
redirect
(
reverse
(
'courseware'
,
args
=
[
course
.
id
.
to_deprecated_string
()]))
raise
Http404
# Allow chromeless operation
if
section_descriptor
.
chrome
:
chrome
=
[
s
.
strip
()
for
s
in
section_descriptor
.
chrome
.
lower
()
.
split
(
","
)]
if
'accordion'
not
in
chrome
:
context
[
'disable_accordion'
]
=
True
if
'tabs'
not
in
chrome
:
context
[
'disable_tabs'
]
=
True
if
section_descriptor
.
default_tab
:
context
[
'default_tab'
]
=
section_descriptor
.
default_tab
# cdodge: this looks silly, but let's refetch the section_descriptor with depth=None
# which will prefetch the children more efficiently than doing a recursive load
section_descriptor
=
modulestore
()
.
get_item
(
section_descriptor
.
location
,
depth
=
None
)
# Load all descendants of the section, because we're going to display its
# html, which in general will need all of its children
field_data_cache
.
add_descriptor_descendents
(
section_descriptor
,
depth
=
None
)
section_module
=
get_module_for_descriptor
(
user
,
request
,
section_descriptor
,
field_data_cache
,
course_key
,
position
,
course
=
course
)
# Save where we are in the chapter.
save_child_position
(
chapter_descriptor
,
section
)
table_of_contents
,
prev_section_info
,
next_section_info
=
toc_for_course
(
user
,
request
,
course
,
chapter
,
section
,
field_data_cache
)
context
[
'accordion'
]
=
render_accordion
(
request
,
course
,
table_of_contents
)
def
_compute_section_url
(
section_info
,
requested_child
):
"""
Returns the section URL for the given section_info with the given child parameter.
"""
return
"{url}?child={requested_child}"
.
format
(
url
=
reverse
(
'courseware_section'
,
args
=
[
unicode
(
course
.
id
),
section_info
[
'chapter_url_name'
],
section_info
[
'url_name'
]],
),
requested_child
=
requested_child
,
)
section_render_context
=
{
'activate_block_id'
:
request
.
GET
.
get
(
'activate_block_id'
),
'requested_child'
:
request
.
GET
.
get
(
"child"
),
'prev_url'
:
_compute_section_url
(
prev_section_info
,
'last'
)
if
prev_section_info
else
None
,
'next_url'
:
_compute_section_url
(
next_section_info
,
'first'
)
if
next_section_info
else
None
,
}
context
[
'fragment'
]
=
section_module
.
render
(
STUDENT_VIEW
,
section_render_context
)
context
[
'section_title'
]
=
section_descriptor
.
display_name_with_default_escaped
result
=
render_to_response
(
'courseware/courseware.html'
,
context
)
except
Exception
as
e
:
# Doesn't bar Unicode characters from URL, but if Unicode characters do
# cause an error it is a graceful failure.
if
isinstance
(
e
,
UnicodeEncodeError
):
raise
Http404
(
"URL contains Unicode characters"
)
if
isinstance
(
e
,
Http404
):
# let it propagate
raise
# In production, don't want to let a 500 out for any reason
if
settings
.
DEBUG
:
raise
else
:
log
.
exception
(
u"Error in index view: user=
%
s, effective_user=
%
s, course=
%
s, chapter=
%
s section=
%
s position=
%
s"
,
request
.
user
,
user
,
course
,
chapter
,
section
,
position
)
try
:
result
=
render_to_response
(
'courseware/courseware-error.html'
,
{
'staff_access'
:
staff_access
,
'course'
:
course
})
except
:
# Let the exception propagate, relying on global config to at
# at least return a nice error message
log
.
exception
(
"Error while rendering courseware-error page"
)
raise
return
result
@ensure_csrf_cookie
@ensure_csrf_cookie
@ensure_valid_course_key
@ensure_valid_course_key
def
jump_to_id
(
request
,
course_id
,
module_id
):
def
jump_to_id
(
request
,
course_id
,
module_id
):
...
@@ -627,10 +244,12 @@ def jump_to(_request, course_id, location):
...
@@ -627,10 +244,12 @@ def jump_to(_request, course_id, location):
except
InvalidKeyError
:
except
InvalidKeyError
:
raise
Http404
(
u"Invalid course_key or usage_key"
)
raise
Http404
(
u"Invalid course_key or usage_key"
)
try
:
try
:
user
=
_request
.
user
redirect_url
=
get_redirect_url
(
course_key
,
usage_key
)
redirect_url
=
get_redirect_url
(
course_key
,
usage_key
)
if
GlobalStaff
()
.
has_user
(
user
)
and
not
CourseEnrollment
.
is_enrolled
(
user
,
course_key
):
user
=
_request
.
user
redirect_url
=
get_redirect_url_for_global_staff
(
course_key
,
usage_key
)
user_is_global_staff
=
GlobalStaff
()
.
has_user
(
user
)
user_is_enrolled
=
CourseEnrollment
.
is_enrolled
(
user
,
course_key
)
if
user_is_global_staff
and
not
user_is_enrolled
:
redirect_url
=
get_redirect_url_for_global_staff
(
course_key
,
_next
=
redirect_url
)
except
ItemNotFoundError
:
except
ItemNotFoundError
:
raise
Http404
(
u"No data at this location: {0}"
.
format
(
usage_key
))
raise
Http404
(
u"No data at this location: {0}"
.
format
(
usage_key
))
except
NoPathToItem
:
except
NoPathToItem
:
...
@@ -838,18 +457,18 @@ def get_cosmetic_display_price(course, registration_price):
...
@@ -838,18 +457,18 @@ def get_cosmetic_display_price(course, registration_price):
class
EnrollStaffView
(
View
):
class
EnrollStaffView
(
View
):
"""
"""
Determine If user is global staff, it will be redirected to page "enroll_satff.html"
Displays view for registering in the course to a global staff user.
that asks you if you want to register for the course.
This pages has the courseware link you were heading to as a ?next parameter
User can either choose to 'Enroll' or 'Don't Enroll' in the course.
Click "enroll" and be redirected to the page you wanted to go to
Enroll: Enrolls user in course and redirects to the courseware.
Click "Don't enroll" and go back to the course about page
Don't Enroll: Redirects user to course about page.
Arguments:
Arguments:
- request : HTTP request
- request : HTTP request
- course_id : course id
- course_id : course id
Returns:
Returns:
-RedirectResponse
-
RedirectResponse
"""
"""
template_name
=
'enroll_staff.html'
template_name
=
'enroll_staff.html'
...
@@ -857,37 +476,40 @@ class EnrollStaffView(View):
...
@@ -857,37 +476,40 @@ class EnrollStaffView(View):
@method_decorator
(
ensure_valid_course_key
)
@method_decorator
(
ensure_valid_course_key
)
def
get
(
self
,
request
,
course_id
):
def
get
(
self
,
request
,
course_id
):
"""
"""
Renders Enroll Staff View
Display enroll staff view to global staff user with `Enroll` and `Don't Enroll` options.
"""
"""
user
=
request
.
user
user
=
request
.
user
course_key
=
from_string_or_404
(
course_id
)
course_key
=
CourseKey
.
from_string
(
course_id
)
with
modulestore
()
.
bulk_operations
(
course_key
):
with
modulestore
()
.
bulk_operations
(
course_key
):
course
=
get_course_with_access
(
user
,
'load'
,
course_key
)
course
=
get_course_with_access
(
user
,
'load'
,
course_key
)
if
not
registered_for_course
(
course
,
user
):
if
not
registered_for_course
(
course
,
user
):
context
=
{
'course'
:
course
,
context
=
{
'csrftoken'
:
csrf
(
request
)[
"csrf_token"
]}
'course'
:
course
,
'csrftoken'
:
csrf
(
request
)[
"csrf_token"
]
}
return
render_to_response
(
self
.
template_name
,
context
)
return
render_to_response
(
self
.
template_name
,
context
)
@method_decorator
(
require_global_staff
)
@method_decorator
(
require_global_staff
)
@method_decorator
(
ensure_valid_course_key
)
@method_decorator
(
ensure_valid_course_key
)
def
post
(
self
,
request
,
course_id
):
def
post
(
self
,
request
,
course_id
):
"""
"""
Enroll and returns the response
Either enrolls the user in course or redirects user to course about page
depending upon the option (Enroll, Don't Enroll) chosen by the user.
"""
"""
_next
=
urllib
.
quote_plus
(
request
.
GET
.
get
(
'next'
,
'info'
),
safe
=
'/:?='
)
_next
=
urllib
.
quote_plus
(
request
.
GET
.
get
(
'next'
,
'info'
),
safe
=
'/:?='
)
course_key
=
from_string_or_404
(
course_id
)
course_key
=
CourseKey
.
from_string
(
course_id
)
if
'enroll'
in
request
.
POST
:
enroll
=
'enroll'
in
request
.
POST
CourseEnrollment
.
enroll
(
request
.
user
,
course_key
)
if
enroll
:
add_enrollment
(
request
.
user
.
username
,
course_id
)
log
.
info
(
log
.
info
(
u"User
%
s enrolled in
%
s via `enroll_staff` view"
,
u"User
%
s enrolled in
%
s via `enroll_staff` view"
,
request
.
user
.
username
,
request
.
user
.
username
,
course_id
course_id
)
)
return
redirect
(
_next
)
return
redirect
(
_next
)
elif
'dont_enroll'
in
request
.
POST
:
return
redirect
(
reverse
(
'about_course'
,
args
=
[
unicode
(
course_key
)]))
# In any other case redirect to the course about page.
else
:
return
redirect
(
reverse
(
'about_course'
,
args
=
[
unicode
(
course_key
)]))
raise
Http404
@ensure_csrf_cookie
@ensure_csrf_cookie
...
...
lms/templates/enroll_staff.html
View file @
48e7fc81
...
@@ -12,30 +12,34 @@
...
@@ -12,30 +12,34 @@
</
%
block>
</
%
block>
<
%
block
name=
"pagetitle"
>
${course.display_name_with_default}
</
%
block>
<
%
block
name=
"pagetitle"
>
${course.display_name_with_default}
</
%
block>
<main
id=
"main"
aria-label=
"Content"
tabindex=
"-1"
>
<section
class=
"course-info"
>
<div
class=
"course-info"
>
<header
class=
"course-profile"
>
<header
class=
"course-profile"
>
<div
class=
"intro-inner-wrapper"
>
<div
class=
"intro-inner-wrapper"
>
<div
class=
"table"
>
<div
class=
"table"
>
<section
class=
"intro"
>
<div
class=
"intro"
>
<div
class=
"heading-group"
>
<div
class=
"heading-group"
>
<h3>
${_("You should Register before trying to access the Unit")}
</h3>
<h3>
${_("You should Register before trying to access the Unit")}
</h3>
</div>
<div
class=
"heading-group"
>
<h1>
${course.display_name_with_default}
<a
href=
"#"
>
${course.display_org_with_default}
</a>
</h1>
</div>
<form
role=
"form"
id=
"enroll_staff_form"
method=
"post"
action=
""
>
<input
type=
"hidden"
name=
"csrfmiddlewaretoken"
value=
"${ csrftoken }"
/>
<div
class=
"main-cta"
>
<input
class=
"register"
name=
"enroll"
type=
"submit"
value=
"${_('Enroll')}"
/>
<input
class=
"register"
name=
"dont_enroll"
type=
"submit"
value=
"${_('Don\'t enroll')}"
/>
</div>
</div>
</form>
<div
class=
"heading-group"
>
</section>
<p>
${course.display_name_with_default}
</p>
</div>
<form
role=
"form"
id=
"enroll_staff_form"
method=
"post"
action=
""
>
<input
type=
"hidden"
name=
"csrfmiddlewaretoken"
value=
"${ csrftoken }"
/>
<div
class=
"main-cta"
>
<button
class=
"register"
name=
"enroll"
type=
"submit"
value=
"${_('Enroll')}"
>
${_('Enroll')}
<span
class=
"sr"
>
${course.display_name_with_default}
</span></button>
<button
class=
"register"
name=
"dont_enroll"
type=
"submit"
value=
"${_('Don\'t enroll')}"
>
${_('Don\'t enroll')}
<span
class=
"sr"
>
${course.display_name_with_default}
</span></button>
</div>
</form>
</div>
</div>
</div>
</div>
</
div
>
</
header
>
</
header
>
</
div
>
</
sectio
n>
</
mai
n>
lms/urls.py
View file @
48e7fc81
...
@@ -10,7 +10,7 @@ from django.conf.urls.static import static
...
@@ -10,7 +10,7 @@ from django.conf.urls.static import static
from
microsite_configuration
import
microsite
from
microsite_configuration
import
microsite
import
auth_exchange.views
import
auth_exchange.views
from
courseware.views
import
EnrollStaffView
from
courseware.views
.views
import
EnrollStaffView
from
config_models.views
import
ConfigurationModelCurrentAPIView
from
config_models.views
import
ConfigurationModelCurrentAPIView
from
courseware.views.index
import
CoursewareIndex
from
courseware.views.index
import
CoursewareIndex
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
...
...
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