Commit 9008548c by Sarina Canelake

Merge pull request #8207 from amir-qayyum-khan/add_ccx_enable_to_settings

Added ccx enable/disable flag to advance settings and show hide ccx coach option on lms
parents 46cb847e 6a41cd7b
......@@ -83,6 +83,10 @@ class CourseMetadata(object):
if not settings.FEATURES.get('ENABLE_VIDEO_BUMPER'):
filtered_list.append('video_bumper')
# Do not show enable_ccx if feature is not enabled.
if not settings.FEATURES.get('CUSTOM_COURSES_EDX'):
filtered_list.append('enable_ccx')
return filtered_list
@classmethod
......
......@@ -386,6 +386,21 @@ class CourseFields(object):
),
scope=Scope.settings
)
enable_ccx = Boolean(
# Translators: Custom Courses for edX (CCX) is an edX feature for re-using course content. CCX Coach is
# a role created by a course Instructor to enable a person (the "Coach") to manage the custom course for
# his students.
display_name=_("Enable CCX"),
# Translators: Custom Courses for edX (CCX) is an edX feature for re-using course content. CCX Coach is
# a role created by a course Instructor to enable a person (the "Coach") to manage the custom course for
# his students.
help=_(
"Allow course instructors to assign CCX Coach roles, and allow coaches to manage Custom Courses on edX."
" When false, Custom Courses cannot be created, but existing Custom Courses will be preserved."
),
default=False,
scope=Scope.settings
)
allow_anonymous = Boolean(
display_name=_("Allow Anonymous Discussion Posts"),
help=_("Enter true or false. If true, students can create discussion posts that are anonymous to all users."),
......
......@@ -758,7 +758,7 @@ class CcxCoachTab(CourseTab):
the user is one.
"""
user_is_coach = False
if settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
if settings.FEATURES.get('CUSTOM_COURSES_EDX', False) and course.enable_ccx:
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from student.roles import CourseCcxCoachRole # pylint: disable=import-error
from ccx.overrides import get_current_request # pylint: disable=import-error
......
......@@ -5,7 +5,9 @@ import datetime
import json
import re
import pytz
from mock import patch
import ddt
import unittest
from mock import patch, MagicMock
from nose.plugins.attrib import attr
from capa.tests.response_xml_factory import StringResponseXMLFactory
......@@ -14,6 +16,7 @@ from courseware.tests.factories import StudentModuleFactory # pylint: disable=i
from courseware.tests.helpers import LoginEnrollmentTestCase # pylint: disable=import-error
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.test import RequestFactory
from edxmako.shortcuts import render_to_response # pylint: disable=import-error
from student.roles import CourseCcxCoachRole # pylint: disable=import-error
from student.tests.factories import ( # pylint: disable=import-error
......@@ -22,12 +25,14 @@ from student.tests.factories import ( # pylint: disable=import-error
UserFactory,
)
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.x_module import XModuleMixin
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import (
CourseFactory,
ItemFactory,
)
import xmodule.tabs as tabs
from ..models import (
CustomCourseForEdX,
CcxMembership,
......@@ -56,6 +61,17 @@ def intercept_renderer(path, context):
return response
def ccx_dummy_request():
"""
Returns dummy request object for CCX coach tab test
"""
factory = RequestFactory()
request = factory.get('ccx_coach_dashboard')
request.user = MagicMock()
return request
@attr('shard_1')
class TestCoachDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
......@@ -756,6 +772,48 @@ class TestSwitchActiveCCX(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.verify_active_ccx(self.client)
@ddt.ddt
class CCXCoachTabTestCase(unittest.TestCase):
"""
Test case for CCX coach tab.
"""
def setUp(self):
super(CCXCoachTabTestCase, self).setUp()
self.course = MagicMock()
self.course.id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')
self.settings = MagicMock()
self.settings.FEATURES = {}
def check_ccx_tab(self):
"""Helper function for verifying the ccx tab."""
tab = tabs.CcxCoachTab({'type': tabs.CcxCoachTab.type, 'name': 'CCX Coach'})
return tab
@ddt.data(
(True, True, True),
(True, False, False),
(False, True, False),
(False, False, False),
(True, None, False)
)
@patch('ccx.overrides.get_current_request', ccx_dummy_request)
@ddt.unpack
def test_coach_tab_for_ccx_advance_settings(self, ccx_feature_flag, enable_ccx, expected_result):
"""
Test ccx coach tab state (visible or hidden) depending on the value of enable_ccx flag, ccx feature flag.
"""
tab = self.check_ccx_tab()
self.settings.FEATURES = {'CUSTOM_COURSES_EDX': ccx_feature_flag}
self.course.enable_ccx = enable_ccx
self.assertEquals(
expected_result,
tab.can_display(
self.course, self.settings, is_user_authenticated=True, is_user_staff=False, is_user_enrolled=True
)
)
def flatten(seq):
"""
For [[1, 2], [3, 4]] returns [1, 2, 3, 4]. Does not recurse.
......
"""
Unit tests for instructor_dashboard.py.
"""
import ddt
from mock import patch
from django.conf import settings
......@@ -16,6 +17,7 @@ from course_modes.models import CourseMode
from student.roles import CourseFinanceAdminRole
@ddt.ddt
class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
Tests for the instructor dashboard (not legacy).
......@@ -179,3 +181,29 @@ class TestInstructorDashboard(ModuleStoreTestCase, LoginEnrollmentTestCase):
total_amount = single_purchase_total + bulk_purchase_total
response = self.client.get(self.url)
self.assertIn('{currency}{amount}'.format(currency='$', amount=total_amount), response.content)
@ddt.data(
(True, True, True),
(True, False, False),
(True, None, False),
(False, True, False),
(False, False, False),
(False, None, False),
)
@ddt.unpack
def test_ccx_coaches_option_on_admin_list_management_instructor(
self, ccx_feature_flag, enable_ccx, expected_result
):
"""
Test whether the "CCX Coaches" option is visible or hidden depending on the value of course.enable_ccx.
"""
with patch.dict(settings.FEATURES, {'CUSTOM_COURSES_EDX': ccx_feature_flag}):
self.course.enable_ccx = enable_ccx
self.store.update_item(self.course, self.instructor.id)
response = self.client.get(self.url)
self.assertEquals(
expected_result,
'CCX Coaches are able to create their own Custom Courses based on this course' in response.content
)
......@@ -324,10 +324,12 @@ def _section_course_info(course, access):
def _section_membership(course, access):
""" Provide data for the corresponding dashboard section """
course_key = course.id
ccx_enabled = settings.FEATURES.get('CUSTOM_COURSES_EDX', False) and course.enable_ccx
section_data = {
'section_key': 'membership',
'section_display_name': _('Membership'),
'access': access,
'ccx_is_enabled': ccx_enabled,
'enroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': unicode(course_key)}),
'unenroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': unicode(course_key)}),
'upload_student_csv_button_url': reverse('register_and_enroll_students', kwargs={'course_id': unicode(course_key)}),
......
......@@ -243,8 +243,8 @@
data-add-button-label="${_("Add Community TA")}"
></div>
%endif
%if section_data['access']['instructor'] and settings.FEATURES.get('CUSTOM_COURSES_EDX', False):
%if section_data['access']['instructor'] and section_data['ccx_is_enabled']:
<div class="auth-list-container"
data-rolename="ccx_coach"
data-display-name="${_("CCX Coaches")}"
......
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