Commit 48e7fc81 by attiyaishaque

Bokchoy Test Deleted.

parent 275a31ec
...@@ -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()
...@@ -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?
......
""" """
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())
...@@ -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})
......
...@@ -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
...@@ -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):
......
...@@ -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
......
...@@ -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>
</section> </main>
...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment