Commit 66d03689 by Dennis Jen

Updated learner analytics from switch to flag.

* upgraded waffle
* changed enable_learner_analytics to display_learner_analytics
parent 70ab07b6
......@@ -60,7 +60,12 @@ The following switches are available:
| enable_video_preview | Enable video preview. |
| display_names_for_course_index | Display course names on course index page. |
| display_course_name_in_nav | Display course name in navigation bar. |
| enable_learner_analytics | Enable Learner Analytics app and API |
The following flags are available:
| Flag | Purpose |
|--------------------------------|-------------------------------------------------------|
| display_learner_analytics | Display Learner Analytics links |
Authentication & Authorization
------------------------------
......
......@@ -76,4 +76,4 @@ if ENABLE_COURSE_API and not (COURSE_API_URL and COURSE_API_KEY):
ENABLE_VIDEO_PREVIEW = str2bool(os.environ.get('ENABLE_VIDEO_PREVIEW', False))
# Learner analytics
ENABLE_LEARNER_ANALYTICS = str2bool(os.environ.get('ENABLE_LEARNER_ANALYTICS', False))
DISPLAY_LEARNER_ANALYTICS = str2bool(os.environ.get('DISPLAY_LEARNER_ANALYTICS', False))
......@@ -2,12 +2,12 @@ from unittest import skipUnless
from bok_choy.web_app_test import WebAppTest
from acceptance_tests import ENABLE_LEARNER_ANALYTICS
from acceptance_tests import DISPLAY_LEARNER_ANALYTICS
from acceptance_tests.mixins import CoursePageTestsMixin
from acceptance_tests.pages import CourseLearnersPage
@skipUnless(ENABLE_LEARNER_ANALYTICS, 'Learner Analytics must be enabled to run CourseLearnersTests')
@skipUnless(DISPLAY_LEARNER_ANALYTICS, 'Learner Analytics must be enabled to run CourseLearnersTests')
class CourseLearnersTests(CoursePageTestsMixin, WebAppTest):
help_path = 'learners/Learner_Activity.html'
......
from waffle import Switch
class FeatureTestCaseMixin(object):
def assertElementBehindFeature(self, url, selector, feature_name):
# No interface with feature not created
response = self.client.get(url)
self.assertNotIn(selector, response.content)
# Create the feature
switch = Switch.objects.create(name=feature_name, active=False)
# No interface with feature disabled
response = self.client.get(url)
self.assertNotIn(selector, response.content)
# Interface should be present with feature enabled
switch.active = True
switch.save()
response = self.client.get(url)
self.assertIn(selector, response.content)
from waffle import Switch
class SwitchMixin(object):
@classmethod
def toggle_switch(cls, name, active):
switch, _created = Switch.objects.get_or_create(name=name)
switch.active = active
switch.save()
......@@ -2,14 +2,17 @@ from __future__ import division
import copy
import datetime
import analyticsclient.constants.activity_type as AT
from analyticsclient.constants import enrollment_modes
from django.conf import settings
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.test import (override_settings, TestCase)
import mock
from ddt import ddt, data, unpack
import mock
from waffle.testutils import override_switch
import analyticsclient.constants.activity_type as AT
from analyticsclient.constants import enrollment_modes
from common.tests.course_fixtures import (
ChapterFixture,
......@@ -24,7 +27,7 @@ from courses.presenters import BasePresenter
from courses.presenters.engagement import (CourseEngagementActivityPresenter, CourseEngagementVideoPresenter)
from courses.presenters.enrollment import (CourseEnrollmentPresenter, CourseEnrollmentDemographicsPresenter)
from courses.presenters.performance import CoursePerformancePresenter
from courses.tests import (SwitchMixin, utils)
from courses.tests import utils
from courses.tests.factories import (CourseEngagementDataFactory, CoursePerformanceDataFactory)
......@@ -54,7 +57,7 @@ class BasePresenterTests(TestCase):
self.assertEqual(self.presenter.get_current_date(), datetime.datetime.utcnow().strftime(dt_format))
class CourseEngagementActivityPresenterTests(SwitchMixin, TestCase):
class CourseEngagementActivityPresenterTests(TestCase):
def setUp(self):
super(CourseEngagementActivityPresenterTests, self).setUp()
......@@ -102,34 +105,33 @@ class CourseEngagementActivityPresenterTests(SwitchMixin, TestCase):
return trends
def assertSummaryAndTrendsValid(self, include_forum_activity, expected_trends):
self.toggle_switch('show_engagement_forum_activity', include_forum_activity)
summary, trends = self.presenter.get_summary_and_trend_data()
# Validate the trends
self.assertEqual(len(expected_trends), len(trends))
self.assertDictEqual(expected_trends[0], trends[0])
self.assertDictEqual(expected_trends[1], trends[1])
# Validate the summary
expected_summary = utils.mock_course_activity()[1]
del expected_summary['created']
del expected_summary['interval_end']
del expected_summary['course_id']
expected_summary.update({
'attempted_problem_percent_str': u"3.0% of current students",
'posted_forum_percent_str': "--",
'played_video_percent_str': u"10.0% of current students",
'any_percent_str': u"< 1% of current students",
})
if not include_forum_activity:
del expected_summary[AT.POSTED_FORUM]
del expected_summary['posted_forum_percent_str']
expected_summary['last_updated'] = utils.CREATED_DATETIME
self.assertDictEqual(summary, expected_summary)
with override_switch('show_engagement_forum_activity', active=include_forum_activity):
summary, trends = self.presenter.get_summary_and_trend_data()
# Validate the trends
self.assertEqual(len(expected_trends), len(trends))
self.assertDictEqual(expected_trends[0], trends[0])
self.assertDictEqual(expected_trends[1], trends[1])
# Validate the summary
expected_summary = utils.mock_course_activity()[1]
del expected_summary['created']
del expected_summary['interval_end']
del expected_summary['course_id']
expected_summary.update({
'attempted_problem_percent_str': u"3.0% of current students",
'posted_forum_percent_str': "--",
'played_video_percent_str': u"10.0% of current students",
'any_percent_str': u"< 1% of current students",
})
if not include_forum_activity:
del expected_summary[AT.POSTED_FORUM]
del expected_summary['posted_forum_percent_str']
expected_summary['last_updated'] = utils.CREATED_DATETIME
self.assertDictEqual(summary, expected_summary)
@mock.patch('analyticsclient.course.Course.activity', mock.Mock(side_effect=utils.mock_course_activity))
@mock.patch('analyticsclient.course.Course.enrollment', mock.Mock(side_effect=utils.mock_course_enrollment))
......@@ -148,7 +150,7 @@ class CourseEngagementActivityPresenterTests(SwitchMixin, TestCase):
@ddt
class CourseEngagementVideoPresenterTests(SwitchMixin, TestCase):
class CourseEngagementVideoPresenterTests(TestCase):
SECTION_ID = 'i4x://edX/DemoX/chapter/9fca584977d04885bc911ea76a9ef29e'
SUBSECTION_ID = 'i4x://edX/DemoX/sequential/07bc32474380492cb34f76e5f9d9a135'
VIDEO_ID = 'i4x://edX/DemoX/video/0b9e39477cf34507a7a48f74be381fdd'
......@@ -579,7 +581,7 @@ class CourseEngagementVideoPresenterTests(SwitchMixin, TestCase):
self.assertEqual(expected_url, self.presenter.build_render_xblock_url(xblock_render_base, self.VIDEO_ID))
class CourseEnrollmentPresenterTests(SwitchMixin, TestCase):
class CourseEnrollmentPresenterTests(TestCase):
def setUp(self):
self.course_id = 'edX/DemoX/Demo_Course'
......
from django.test import TestCase
from waffle import Switch
from django.contrib.auth.models import AnonymousUser
from django.test import RequestFactory, TestCase
from waffle.testutils import override_flag, override_switch
import courses.utils as utils
class UtilsTest(TestCase):
def test_is_feature_enabled(self):
name = 'test-switch'
item = {'switch': name}
request = RequestFactory().get('/')
request.user = AnonymousUser()
# Return True if no switch provided
self.assertTrue(utils.is_feature_enabled({'switch': None}))
# Return True if no switch or flag are provided
self.assertTrue(utils.is_feature_enabled({'switch': None, 'flag': None}, request))
name = 'test-waffle'
item = {'switch': 'test-waffle'}
# Return False if switch inactive
switch = Switch.objects.create(name=name, active=False)
self.assertFalse(utils.is_feature_enabled(item))
with override_switch(name, active=False):
self.assertFalse(utils.is_feature_enabled(item, request))
# Return True if switch active
switch.active = True
switch.save()
self.assertTrue(utils.is_feature_enabled(item))
with override_switch(name, active=True):
self.assertTrue(utils.is_feature_enabled(item, request))
item = {'flag': 'test-waffle'}
# Return False if flag inactive
with override_flag(name, active=False):
self.assertFalse(utils.is_feature_enabled(item, request))
# Return True if flag active
with override_flag(name, active=True):
self.assertTrue(utils.is_feature_enabled(item, request))
class NumberTests(TestCase):
......
......@@ -11,10 +11,10 @@ from django.utils.translation import ugettext_lazy as _
import httpretty
import mock
from mock import patch, Mock, _is_started
from waffle.testutils import override_switch
from core.tests.test_views import RedirectTestCaseMixin, UserTestCaseMixin
from courses.permissions import set_user_course_permissions, revoke_user_course_permissions
from courses.tests import SwitchMixin
from courses.tests.utils import set_empty_permissions, get_mock_api_enrollment_data, mock_course_name
......@@ -24,7 +24,8 @@ DEPRECATED_DEMO_COURSE_ID = 'edX/DemoX/Demo_Course'
logger = logging.getLogger(__name__)
class CourseAPIMixin(SwitchMixin):
@override_switch('enable_course_api', active=True)
class CourseAPIMixin(object):
"""
Mixin with methods to help mock the course API.
"""
......@@ -32,10 +33,6 @@ class CourseAPIMixin(SwitchMixin):
{'id': course_key, 'name': 'Test ' + course_key} for course_key in [DEMO_COURSE_ID, DEPRECATED_DEMO_COURSE_ID]
]}
def setUp(self, *args, **kwargs):
super(CourseAPIMixin, self).setUp(*args, **kwargs)
self.toggle_switch('enable_course_api', True)
def mock_course_api(self, path, body=None, **kwargs):
"""
Registers an HTTP mock for the specified course API path. The mock returns the specified data.
......@@ -188,9 +185,9 @@ class CourseViewTestMixin(CourseAPIMixin, NavAssertMixin, ViewTestMixin):
@httpretty.activate
@data(DEMO_COURSE_ID, DEPRECATED_DEMO_COURSE_ID)
@override_switch('enable_course_api', active=True)
@override_switch('display_course_name_in_nav', active=True)
def test_valid_course(self, course_id):
self.toggle_switch('enable_course_api', True)
self.toggle_switch('display_course_name_in_nav', True)
self.mock_course_detail(course_id)
self.assertViewIsValid(course_id)
......
......@@ -4,7 +4,6 @@ from django.test import TestCase
import mock
from analyticsclient.exceptions import NotFoundError
from courses.tests import SwitchMixin
from courses.tests.test_views import ViewTestMixin, DEMO_COURSE_ID, DEPRECATED_DEMO_COURSE_ID
from courses.tests.utils import convert_list_of_dicts_to_csv, get_mock_api_enrollment_geography_data, \
get_mock_api_enrollment_data, get_mock_api_course_activity, get_mock_api_enrollment_age_data, \
......@@ -84,7 +83,7 @@ class CourseEnrollmentCSVViewTests(CourseCSVTestMixin, TestCase):
return get_mock_api_enrollment_data(course_id)
class CourseEnrollmentModeCSVViewTests(SwitchMixin, CourseCSVTestMixin, TestCase):
class CourseEnrollmentModeCSVViewTests(CourseCSVTestMixin, TestCase):
viewname = 'courses:csv:enrollment'
column_headings = ['count', 'course_id', 'date', 'audit', 'honor', 'professional', 'verified']
base_file_name = 'enrollment'
......
from ddt import ddt
import httpretty
import mock
from mock import patch, Mock
import httpretty
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from waffle.testutils import override_switch
import analyticsclient.constants.activity_type as AT
from courses.tests.factories import CourseEngagementDataFactory
......@@ -19,13 +21,13 @@ from courses.tests.test_views import (
from courses.tests import utils
@override_switch('enable_engagement_videos_pages', active=True)
class CourseEngagementViewTestMixin(PatchMixin, CourseAPIMixin): # pylint: disable=abstract-method
api_method = 'analyticsclient.course.Course.activity'
active_secondary_nav_label = None
def setUp(self):
super(CourseEngagementViewTestMixin, self).setUp()
self.toggle_switch('enable_engagement_videos_pages', True)
# This view combines the activity API with the enrollment API, so we need to mock both.
patcher = mock.patch('analyticsclient.course.Course.enrollment', return_value=utils.mock_course_enrollment())
patcher.start()
......@@ -65,6 +67,7 @@ class CourseEngagementViewTestMixin(PatchMixin, CourseAPIMixin): # pylint: disa
self.assertListEqual(nav, expected)
@override_switch('enable_engagement_videos_pages', active=True)
@ddt
class CourseEngagementContentViewTests(CourseViewTestMixin, CourseEngagementViewTestMixin, TestCase):
viewname = 'courses:engagement:content'
......@@ -129,6 +132,7 @@ class CourseEngagementContentViewTests(CourseViewTestMixin, CourseEngagementView
self.assertIsNone(context['js_data']['course']['engagementTrends'])
@override_switch('enable_engagement_videos_pages', active=True)
@ddt
class CourseEngagementVideoMixin(CourseEngagementViewTestMixin, CourseStructureViewMixin):
active_secondary_nav_label = 'Video'
......
......@@ -11,26 +11,18 @@ from testfixtures import LogCapture
from django.conf import settings
from django.test import TestCase
from courses.tests import SwitchMixin
from waffle.testutils import override_flag
from courses.tests.test_views import DEMO_COURSE_ID, ViewTestMixin
@httpretty.activate
@override_flag('display_learner_analytics', active=True)
@ddt
class LearnersViewTests(ViewTestMixin, SwitchMixin, TestCase):
class LearnersViewTests(ViewTestMixin, TestCase):
TABLE_ERROR_TEXT = 'We are unable to load this table.'
viewname = 'courses:learners:learners'
@classmethod
def setUpClass(cls, *args, **kwargs):
super(LearnersViewTests, cls).setUpClass(*args, **kwargs)
cls.toggle_switch('enable_learner_analytics', True)
@classmethod
def tearDownClass(cls, *args, **kwargs):
super(LearnersViewTests, cls).tearDownClass(*args, **kwargs)
cls.toggle_switch('enable_learner_analytics', False)
def _register_uris(self, learners_status, learners_payload, course_metadata_status, course_metadata_payload):
httpretty.register_uri(
httpretty.GET,
......@@ -79,8 +71,8 @@ class LearnersViewTests(ViewTestMixin, SwitchMixin, TestCase):
})
self.assertNotContains(response, self.TABLE_ERROR_TEXT)
@override_flag('display_learner_analytics', active=False)
def test_success_if_hidden(self):
self.toggle_switch('enable_learner_analytics', False)
self.test_success()
@data(Timeout, ConnectionError, ValueError)
......
......@@ -3,6 +3,8 @@
from ddt import data, ddt
import httpretty
import mock
from waffle.testutils import override_switch
from django.test import TestCase
from courses.tests.test_views import ViewTestMixin, CourseViewTestMixin, DEMO_COURSE_ID, DEPRECATED_DEMO_COURSE_ID, \
......@@ -28,8 +30,8 @@ class CourseHomeViewTests(CourseViewTestMixin, TestCase):
self.skipTest('The course homepage does not check for the existence of a course.')
@httpretty.activate
@override_switch('enable_course_api', active=True)
def test_course_overview(self):
self.toggle_switch('enable_course_api', True)
self.mock_course_detail(DEMO_COURSE_ID, {'start': '2015-01-23T00:00:00Z', 'end': None})
response = self.client.get(self.path(course_id=DEMO_COURSE_ID))
self.assertEqual(response.status_code, 200)
......@@ -44,8 +46,8 @@ class CourseHomeViewTests(CourseViewTestMixin, TestCase):
self.assertEqual(links.get('Studio'), 'http://cms-host/{}'.format(DEMO_COURSE_ID))
@httpretty.activate
@override_switch('enable_course_api', active=True)
def test_course_ended(self):
self.toggle_switch('enable_course_api', True)
self.mock_course_detail(DEMO_COURSE_ID, {
'start': '2015-01-01T00:00:00Z',
'end': '2015-02-15T00:00:00Z'
......@@ -94,10 +96,10 @@ class CourseIndexViewTests(CourseAPIMixin, ViewTestMixin, CoursePermissionsExcep
self.assertEqual(response.status_code, 403)
@httpretty.activate
@override_switch('enable_course_api', active=True)
@override_switch('display_names_for_course_index', active=True)
def test_get_with_course_api(self):
""" Verify that the view properly retrieves data from the course API. """
self.toggle_switch('enable_course_api', True)
self.toggle_switch('display_names_for_course_index', True)
self.mock_course_list()
courses = self._create_course_list(DEMO_COURSE_ID, DEPRECATED_DEMO_COURSE_ID, with_name=True)
self.assertIsNotNone(httpretty.last_request())
......
import json
import logging
from analyticsclient.exceptions import ClientError, NotFoundError
from ddt import ddt
import httpretty
from mock import patch, Mock
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.utils.translation import ugettext_lazy as _
import httpretty
from mock import patch, Mock
from waffle.testutils import override_switch
from analyticsclient.exceptions import ClientError, NotFoundError
from courses.tests import utils
from courses.tests.factories import CoursePerformanceDataFactory
......@@ -18,13 +22,12 @@ from courses.tests.test_views import (DEMO_COURSE_ID, CourseStructureViewMixin,
logger = logging.getLogger(__name__)
@ddt
# pylint: disable=abstract-method
@ddt
class CoursePerformanceViewTestMixin(PatchMixin, CourseStructureViewMixin, CourseAPIMixin):
def setUp(self):
super(CoursePerformanceViewTestMixin, self).setUp()
self.toggle_switch('enable_course_api', True)
self.factory = CoursePerformanceDataFactory()
self.factory.course_id = DEMO_COURSE_ID
......@@ -251,6 +254,7 @@ class CoursePerformanceAnswerDistributionMixin(CoursePerformanceViewTestMixin):
self.assertEqual(response.status_code, 404)
@override_switch('enable_course_api', active=True)
@ddt
class CoursePerformanceGradedAnswerDistributionViewTests(CoursePerformanceAnswerDistributionMixin,
CoursePerformanceGradedMixin, TestCase):
......@@ -272,6 +276,7 @@ class CoursePerformanceGradedAnswerDistributionViewTests(CoursePerformanceAnswer
self._test_valid_course(self.factory.presented_assignments[0]['children'][0])
@override_switch('enable_course_api', active=True)
@ddt
class CoursePerformanceUngradedAnswerDistributionViewTests(CoursePerformanceAnswerDistributionMixin,
CoursePerformanceUngradedMixin, TestCase):
......@@ -294,6 +299,7 @@ class CoursePerformanceUngradedAnswerDistributionViewTests(CoursePerformanceAnsw
self._test_valid_course(self.factory.presented_assignments[0]['children'][0])
@override_switch('enable_course_api', active=True)
class CoursePerformanceGradedContentViewTests(CoursePerformanceGradedMixin, TestCase):
viewname = 'courses:performance:graded_content'
......@@ -308,6 +314,7 @@ class CoursePerformanceGradedContentViewTests(CoursePerformanceGradedMixin, Test
self.assertDictContainsSubset(expected, context)
@override_switch('enable_course_api', active=True)
class CoursePerformanceGradedContentByTypeViewTests(CoursePerformanceGradedMixin, TestCase):
viewname = 'courses:performance:graded_content_by_type'
......@@ -348,6 +355,7 @@ class CoursePerformanceGradedContentByTypeViewTests(CoursePerformanceGradedMixin
self.assertEqual(response.status_code, 200)
@override_switch('enable_course_api', active=True)
class CoursePerformanceAssignmentViewTests(CoursePerformanceGradedMixin, TestCase):
viewname = 'courses:performance:assignment'
......@@ -394,6 +402,7 @@ class CoursePerformanceAssignmentViewTests(CoursePerformanceGradedMixin, TestCas
self.assertEqual(response.status_code, 404)
@override_switch('enable_course_api', active=True)
class CoursePerformanceUngradedContentViewTests(CoursePerformanceUngradedMixin, TestCase):
viewname = 'courses:performance:ungraded_content'
......@@ -406,6 +415,7 @@ class CoursePerformanceUngradedContentViewTests(CoursePerformanceUngradedMixin,
self.assertEqual(response.status_code, 200)
@override_switch('enable_course_api', active=True)
class CoursePerformanceUngradedSectionViewTests(CoursePerformanceUngradedMixin, TestCase):
viewname = 'courses:performance:ungraded_section'
......@@ -432,6 +442,7 @@ class CoursePerformanceUngradedSectionViewTests(CoursePerformanceUngradedMixin,
self.assertEqual(response.status_code, 404)
@override_switch('enable_course_api', active=True)
class CoursePerformanceUngradedSubsectionViewTests(CoursePerformanceUngradedMixin, TestCase):
viewname = 'courses:performance:ungraded_subsection'
......
import re
from waffle import switch_is_active
from waffle import flag_is_active, switch_is_active
from opaque_keys.edx.keys import UsageKey
def is_feature_enabled(item):
def is_feature_enabled(item, request):
"""
Returns True if 'switch' or 'flag' are provided and active and True if neither
are provided.
"""
switch_name = item.get('switch', None)
if switch_name:
return switch_is_active(switch_name)
flag_name = item.get('flag', None)
if flag_name:
return flag_is_active(request, flag_name)
return True
......
......@@ -18,7 +18,7 @@ from django.views.generic import TemplateView
from edx_rest_api_client.exceptions import (HttpClientError, SlumberBaseException)
from opaque_keys.edx.keys import CourseKey
import requests
from waffle import switch_is_active
from waffle import flag_is_active, switch_is_active
from analyticsclient.client import Client
from analyticsclient.exceptions import (ClientError, NotFoundError)
......@@ -274,7 +274,7 @@ class CourseNavBarMixin(object):
# Items that will populate the tertiary nav list. This value is optional.
tertiary_nav_items = []
def get_primary_nav_items(self):
def get_primary_nav_items(self, request):
"""
Return the primary nav items.
"""
......@@ -304,25 +304,25 @@ class CourseNavBarMixin(object):
'label': _('Learners'),
'view': 'courses:learners:learners',
'icon': 'fa-users',
'switch': 'enable_learner_analytics'
'flag': 'display_learner_analytics'
}
]
# Remove disabled items
items = filter(is_feature_enabled, items)
items = [item for item in items if is_feature_enabled(item, request)]
# Clean each item
map(self.clean_item, items)
return items
def _build_nav_items(self, nav_items, active_item):
def _build_nav_items(self, nav_items, active_item, request):
# Deep copy the list since it is a list of dictionaries
items = copy.deepcopy(nav_items)
# Process only the nav items that are enabled
items = filter(is_feature_enabled, items)
items = [item for item in items if is_feature_enabled(item, request)]
for item in items:
item['active'] = active_item == item['name']
......@@ -330,17 +330,17 @@ class CourseNavBarMixin(object):
return items
def get_secondary_nav_items(self):
def get_secondary_nav_items(self, request):
"""
Return the secondary nav items.
"""
return self._build_nav_items(self.secondary_nav_items, self.active_secondary_nav_item)
return self._build_nav_items(self.secondary_nav_items, self.active_secondary_nav_item, request)
def get_tertiary_nav_items(self):
def get_tertiary_nav_items(self, request):
"""
Return the tertiary nav items.
"""
return self._build_nav_items(self.tertiary_nav_items, self.active_tertiary_nav_item)
return self._build_nav_items(self.tertiary_nav_items, self.active_tertiary_nav_item, request)
def clean_item(self, item):
"""
......@@ -361,9 +361,9 @@ class CourseNavBarMixin(object):
def get_context_data(self, **kwargs):
context = super(CourseNavBarMixin, self).get_context_data(**kwargs)
primary_nav_items = self.get_primary_nav_items()
secondary_nav_items = self.get_secondary_nav_items()
tertiary_nav_items = self.get_tertiary_nav_items()
primary_nav_items = self.get_primary_nav_items(self.request)
secondary_nav_items = self.get_secondary_nav_items(self.request)
tertiary_nav_items = self.get_tertiary_nav_items(self.request)
# Get the active primary item and remove it from the list
primary_nav_item = None
......@@ -448,7 +448,7 @@ class CourseHome(CourseTemplateWithNavView):
page_name = 'course_home'
page_title = _('Course Home')
def get_table_items(self):
def get_table_items(self, request):
items = []
enrollment_items = {
......@@ -525,7 +525,7 @@ class CourseHome(CourseTemplateWithNavView):
]
})
if switch_is_active('enable_learner_analytics'):
if flag_is_active(request, 'display_learner_analytics'):
items.append({
'name': _('Learners'),
'icon': 'fa-users',
......@@ -564,7 +564,7 @@ class CourseHome(CourseTemplateWithNavView):
def get_context_data(self, **kwargs):
context = super(CourseHome, self).get_context_data(**kwargs)
context.update({
'table_items': self.get_table_items()
'table_items': self.get_table_items(self.request)
})
context['page_data'] = self.get_page_data(context)
......
......@@ -8,13 +8,15 @@ from requests.exceptions import ConnectTimeout
from django.conf import settings
from django.test import TestCase
from waffle.testutils import override_flag
from core.tests.test_views import UserTestCaseMixin
from courses.tests.test_views import PermissionsTestMixin
from courses.tests import SwitchMixin
@override_flag('display_learner_analytics', active=True)
@ddt.ddt
class LearnerAPITestMixin(UserTestCaseMixin, PermissionsTestMixin, SwitchMixin):
class LearnerAPITestMixin(UserTestCaseMixin, PermissionsTestMixin):
"""
Provides test cases and helper methods for learner analytics api test
classes.
......@@ -35,10 +37,6 @@ class LearnerAPITestMixin(UserTestCaseMixin, PermissionsTestMixin, SwitchMixin):
required_query_params = {}
no_permissions_status_code = None
@classmethod
def setUpClass(cls):
cls.toggle_switch('enable_learner_analytics', True)
def assert_response_equals(self, response, expected_status_code, expected_body=None):
self.assertEqual(response.status_code, expected_status_code)
if expected_body is not None:
......
......@@ -9,7 +9,7 @@ django-libsass==0.2 # BSD
django-model-utils==1.5.0 # BSD
djangorestframework==3.3.1 # BSD
django-soapbox==1.1 # BSD
django-waffle==0.10 # BSD
django-waffle==0.11.1 # BSD
edx-auth-backends==0.2.1
edx-django-release-util==0.0.3 # AGPLv3
edx-rest-api-client>=1.5.0, <1.6.0 # Apache
......
......@@ -19,7 +19,7 @@ export LMS_USERNAME=user
export ENABLE_AUTO_AUTH=True
export ENABLE_OAUTH_TESTS=False
export ENABLE_ERROR_PAGE_TESTS=False
export ENABLE_LEARNER_ANALYTICS=True
export DISPLAY_LEARNER_ANALYTICS=True
echo "Migrating Analytics Dashboard DB..."
make migrate
......@@ -34,8 +34,8 @@ cd -
mkdir -p logs
echo "Enabling waffle flags..."
if [[ "${ENABLE_LEARNER_ANALYTICS}" = "True" ]]; then
./manage.py switch enable_learner_analytics on --create
if [[ "${DISPLAY_LEARNER_ANALYTICS}" = "True" ]]; then
./manage.py waffle_flag enable_learner_analytics on --create --everyone
fi
echo "Starting Analytics Data API Server..."
......
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