Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
feat: add toggle for v1 api
Browse files Browse the repository at this point in the history
  • Loading branch information
bseverino committed Nov 15, 2021
1 parent 37f7a79 commit 866bf4e
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# Packaging files:
*.egg*
.python

# Sphinx docs:
build
Expand Down
13 changes: 7 additions & 6 deletions analytics_dashboard/courses/presenters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

class BasePresenter:

def __init__(self, timeout=settings.ANALYTICS_API_DEFAULT_TIMEOUT):
self.client = Client(base_url=settings.DATA_API_URL,
def __init__(self, timeout=settings.ANALYTICS_API_DEFAULT_TIMEOUT, use_v1_api=False):
base_url = settings.DATA_API_URL_V1 if use_v1_api else settings.DATA_API_URL
self.client = Client(base_url=base_url,
auth_token=settings.DATA_API_AUTH_TOKEN,
timeout=timeout)

Expand Down Expand Up @@ -48,8 +49,8 @@ class CoursePresenter(BasePresenter):
This is the base class for the course pages and sets up the analytics client
for the presenters to use to access the data API.
"""
def __init__(self, course_id, timeout=settings.ANALYTICS_API_DEFAULT_TIMEOUT):
super().__init__(timeout)
def __init__(self, course_id, timeout=settings.ANALYTICS_API_DEFAULT_TIMEOUT, use_v1_api=False):
super().__init__(timeout, use_v1_api)
self.course_id = course_id
self.course = self.client.courses(self.course_id)

Expand All @@ -62,8 +63,8 @@ class CourseAPIPresenterMixin(metaclass=abc.ABCMeta):

_last_updated = None

def __init__(self, access_token, course_id, timeout=settings.LMS_DEFAULT_TIMEOUT):
super().__init__(course_id, timeout)
def __init__(self, access_token, course_id, timeout=settings.LMS_DEFAULT_TIMEOUT, use_v1_api=False):
super().__init__(course_id, timeout, use_v1_api)
self.course_api_client = CourseStructureApiClient(settings.COURSE_API_URL, access_token)

def _get_structure(self):
Expand Down
5 changes: 3 additions & 2 deletions analytics_dashboard/courses/presenters/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ class CoursePerformancePresenter(CourseAPIPresenterMixin, CoursePresenter):
# minimum screen space a grading policy bar will take up (even if a policy is 0%, display some bar)
MIN_POLICY_DISPLAY_PERCENT = 5

def __init__(self, access_token, course_id, timeout=settings.LMS_DEFAULT_TIMEOUT):
super().__init__(access_token, course_id, timeout)
def __init__(self, access_token, course_id, timeout=settings.LMS_DEFAULT_TIMEOUT, use_v1_api=False):
super().__init__(access_token, course_id, timeout, use_v1_api)
self.grading_policy_client = CourseStructureApiClient(settings.GRADING_POLICY_API_URL, access_token)
self.use_v1_api = use_v1_api

def course_module_data(self):
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,7 @@ def test_get_course_summary_metrics(self):
'masters_enrollment': 1111,
}
self.assertEqual(metrics, expected)

def test_use_v1_api(self):
presenter = CourseSummariesPresenter(use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def setUp(self):
def test_init(self):
presenter = CoursePresenter('edX/DemoX/Demo_Course')
self.assertEqual(presenter.client.timeout, settings.ANALYTICS_API_DEFAULT_TIMEOUT)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL)

presenter = CoursePresenter('edX/DemoX/Demo_Course', timeout=15)
self.assertEqual(presenter.client.timeout, 15)
Expand All @@ -67,6 +68,10 @@ def test_get_current_date(self):
dt_format = '%Y-%m-%d'
self.assertEqual(self.presenter.get_current_date(), datetime.datetime.utcnow().strftime(dt_format))

def test_use_v1_api(self):
presenter = CoursePresenter('edX/DemoX/Demo_Course', use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)


class CourseEngagementActivityPresenterTests(TestCase):

Expand All @@ -75,6 +80,10 @@ def setUp(self):
self.course_id = 'this/course/id'
self.presenter = CourseEngagementActivityPresenter(self.course_id)

def test_use_v1_api(self):
presenter = CourseEngagementActivityPresenter(self.course_id, use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

def get_expected_trends(self, include_forum_data):
trends = [
{
Expand Down Expand Up @@ -221,6 +230,12 @@ def setUp(self):
self.course_id = 'this/course/id'
self.presenter = CourseEngagementVideoPresenter(settings.COURSE_API_KEY, self.course_id)

def test_use_v1_api(self):
presenter = CourseEngagementVideoPresenter(
settings.COURSE_API_KEY, self.course_id, use_v1_api=True
)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

def test_default_block_data(self):
self.assertDictEqual(self.presenter.default_block_data, {
'users_at_start': 0,
Expand Down Expand Up @@ -650,6 +665,10 @@ def setUp(self):
self.course_id = 'edX/DemoX/Demo_Course'
self.presenter = CourseEnrollmentPresenter(self.course_id)

def test_use_v1_api(self):
presenter = CourseEnrollmentPresenter(self.course_id, use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

@mock.patch('analyticsclient.course.Course.enrollment', mock.Mock(return_value=[]))
def test_get_trend_summary_no_data(self):
actual_summary, actual_trend = self.presenter.get_summary_and_trend_data()
Expand Down Expand Up @@ -758,6 +777,10 @@ def setUp(self):
self.course_id = 'edX/DemoX/Demo_Course'
self.presenter = CourseEnrollmentDemographicsPresenter(self.course_id)

def test_use_v1_api(self):
presenter = CourseEnrollmentDemographicsPresenter(self.course_id, use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

@mock.patch('analyticsclient.course.Course.enrollment')
def test_get_gender(self, mock_gender):
mock_data = utils.get_mock_api_enrollment_gender_data(self.course_id)
Expand Down Expand Up @@ -817,6 +840,12 @@ def setUp(self):
self.presenter = CoursePerformancePresenter(settings.COURSE_API_KEY, self.course_id)
self.factory = CoursePerformanceDataFactory()

def test_use_v1_api(self):
presenter = CoursePerformancePresenter(
settings.COURSE_API_KEY, self.course_id, use_v1_api=True
)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

# First and last response counts were added, insights can handle both types of API responses at the moment.
@data(
annotated(
Expand Down Expand Up @@ -1046,6 +1075,12 @@ def setUp(self):
self.course_id = PERFORMER_PRESENTER_COURSE_ID
self.presenter = TagsDistributionPresenter(settings.COURSE_API_KEY, self.course_id)

def test_use_v1_api(self):
presenter = TagsDistributionPresenter(
settings.COURSE_API_KEY, self.course_id, use_v1_api=True
)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

@data(annotated([{"total_submissions": 21, "correct_submissions": 5,
"tags": {"difficulty": ["Hard"]}},
{"total_submissions": 11, "correct_submissions": 10,
Expand Down Expand Up @@ -1205,6 +1240,10 @@ def setUp(self):
self.course_id = PERFORMER_PRESENTER_COURSE_ID
self.presenter = CourseReportDownloadPresenter(self.course_id)

def test_use_v1_api(self):
presenter = CourseReportDownloadPresenter(self.course_id, use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)

@mock.patch('analyticsclient.course.Course.reports')
def test_report_presenter(self, mock_reports):
api_data = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest.mock as mock
from ddt import data, ddt, unpack
from django.conf import settings
from django.test import TestCase, override_settings

from analytics_dashboard.courses.presenters.programs import ProgramsPresenter
Expand Down Expand Up @@ -78,3 +79,7 @@ def test_get_programs(self, program_ids, course_ids):
actual_programs = presenter.get_programs(program_ids=program_ids, course_ids=course_ids)
self.assertListEqual(actual_programs, self.get_expected_programs(program_ids=program_ids,
course_ids=course_ids))

def test_use_v1_api(self):
presenter = ProgramsPresenter(use_v1_api=True)
self.assertEqual(presenter.client.base_url, settings.DATA_API_URL_V1)
9 changes: 8 additions & 1 deletion analytics_dashboard/courses/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,18 @@ class CourseView(LoginRequiredMixin, CourseValidMixin, CoursePermissionMixin, Te
course_id = None
course_key = None
user = None
api_version = None

def dispatch(self, request, *args, **kwargs):
self.user = request.user
self.course_id = request.course_id
self.course_key = request.course_key

try:
self.api_version = int(request.GET.get('v', 0))
except ValueError:
self.api_version = 0

# some views will catch the NotFoundError to set data to a state that
# the template can rendering a loading error message for the section
try:
Expand All @@ -454,7 +460,8 @@ def dispatch(self, request, *args, **kwargs):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.client = Client(base_url=settings.DATA_API_URL,
base_url = settings.DATA_API_URL_V1 if self.api_version == 1 else settings.DATA_API_URL
self.client = Client(base_url=base_url,
auth_token=settings.DATA_API_AUTH_TOKEN, timeout=settings.LMS_DEFAULT_TIMEOUT)
self.course = self.client.courses(self.course_id)
return context
Expand Down
22 changes: 18 additions & 4 deletions analytics_dashboard/courses/views/course_summaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ def get_context_data(self, **kwargs):
# The user is probably not a course administrator and should not be using this application.
raise PermissionDenied

summaries_presenter = CourseSummariesPresenter()
try:
api_version = int(self.request.GET.get('v', 0))
except ValueError:
api_version = 0

use_v1_api = api_version == 1

summaries_presenter = CourseSummariesPresenter(use_v1_api=use_v1_api)
summaries, last_updated = summaries_presenter.get_course_summaries(courses)

context.update({
Expand All @@ -62,7 +69,7 @@ def get_context_data(self, **kwargs):
}

if enable_course_filters:
programs_presenter = ProgramsPresenter()
programs_presenter = ProgramsPresenter(use_v1_api=use_v1_api)
programs = programs_presenter.get_programs(course_ids=courses)
data['programs_json'] = programs

Expand Down Expand Up @@ -100,7 +107,14 @@ def get_data(self):

enable_course_filters = switch_is_active('enable_course_filters')

presenter = CourseSummariesPresenter()
try:
api_version = int(self.request.GET.get('v', 0))
except ValueError:
api_version = 0

use_v1_api = api_version == 1

presenter = CourseSummariesPresenter(use_v1_api=use_v1_api)
summaries, _ = presenter.get_course_summaries(courses)

if not summaries:
Expand All @@ -112,7 +126,7 @@ def get_data(self):

if enable_course_filters:
# Add list of associated program IDs to each summary entry
programs_presenter = ProgramsPresenter()
programs_presenter = ProgramsPresenter(use_v1_api=use_v1_api)
programs = programs_presenter.get_programs(course_ids=courses)
for summary in summaries:
summary_programs = [program for program in programs if summary['course_id'] in program['course_ids']]
Expand Down
1 change: 1 addition & 0 deletions analytics_dashboard/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@

########## DATA API CONFIGURATION
DATA_API_URL = 'http://127.0.0.1:9001/api/v0'
DATA_API_URL_V1 = 'http://127.0.0.1:9001/api/v1'
DATA_API_AUTH_TOKEN = 'changeme'
########## END DATA API CONFIGURATION

Expand Down
1 change: 1 addition & 0 deletions analytics_dashboard/settings/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
DATABASES['default'][override] = value

DATA_API_URL = os.environ.get("API_SERVER_URL", 'http://edx.devstack.analyticsapi:19001/api/v0')
DATA_API_URL_V1 = os.environ.get("API_SERVER_URL", 'http://edx.devstack.analyticsapi:19001/api/v1')

# Set these to the correct values for your OAuth2/OpenID Connect provider (e.g., devstack)
SOCIAL_AUTH_EDX_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_EDX_OAUTH2_KEY', 'insights-sso-key')
Expand Down
1 change: 1 addition & 0 deletions analytics_dashboard/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

########## DATA API CONFIGURATION
DATA_API_URL = os.getenv("API_SERVER_URL", DATA_API_URL)
DATA_API_URL_V1 = os.getenv("API_SERVER_URL_V1", DATA_API_URL_V1)
########## END DATA API CONFIGURATION

ENABLE_AUTO_AUTH = True
Expand Down
1 change: 1 addition & 0 deletions analytics_dashboard/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
COURSE_API_KEY = 'test_course_api_key'

DATA_API_URL = 'http://data-api-host/api/v0'
DATA_API_URL_V1 = 'http://data-api-host/api/v1'

LOGGING = get_logger_config(debug=DEBUG, dev_env=True, local_loglevel='DEBUG')

0 comments on commit 866bf4e

Please sign in to comment.