Commit c05732b5 by Anjali Pal

Add problem_attempts_per_completed to payload

parent 489e0f6d
DISCUSSION = 'discussion'
PROBLEM = 'problem'
VIDEO = 'video'
INDIVIDUAL_TYPES = [DISCUSSION, PROBLEM, VIDEO]
PROBLEMS = 'problems'
VIDEOS = 'videos'
AGGREGATE_TYPES = [DISCUSSION, PROBLEMS, VIDEOS]
from analytics_data_api.constants import engagement_entity_types
ATTEMPTED = 'attempted'
ATTEMPTS_PER_COMPLETED = 'attempts_per_completed'
COMPLETED = 'completed'
CONTRIBUTED = 'contributed'
VIEWED = 'viewed'
# map entity types to events
EVENTS = {
engagement_entity_types.DISCUSSION: [CONTRIBUTED],
engagement_entity_types.PROBLEM: [ATTEMPTED, ATTEMPTS_PER_COMPLETED, COMPLETED],
engagement_entity_types.PROBLEMS: [ATTEMPTED, COMPLETED],
engagement_entity_types.VIDEO: [VIEWED],
engagement_entity_types.VIDEOS: [VIEWED],
}
DISCUSSION = 'discussion'
PROBLEM = 'problem'
VIDEO = 'video'
PROBLEMS = 'problems'
VIDEOS = 'videos'
INDIVIDUAL_EVENTS = [
'problem_attempts_per_completed',
'problem_attempted',
'problem_completed',
'discussion_contributed',
'video_viewed'
]
EVENTS = [
'problem_attempts_per_completed',
'problems_attempted',
'problems_completed',
'discussion_contributions',
'videos_viewed'
]
from analytics_data_api.constants.engagement_entity_types import DISCUSSION, PROBLEM, VIDEO
from analytics_data_api.constants.engagement_events import ATTEMPTED, COMPLETED, CONTRIBUTED, VIEWED
from analytics_data_api.constants.engagement_events import (ATTEMPTED, ATTEMPTS_PER_COMPLETED, COMPLETED,
CONTRIBUTED, DISCUSSION, PROBLEM, VIDEO, VIEWED)
class EngagementType(object):
......@@ -12,6 +12,7 @@ class EngagementType(object):
# Defines the current canonical set of engagement types used in the Learner
# Analytics API.
ALL_TYPES = (
'problem_attempts_per_completed',
'problems_attempted',
'problems_completed',
'videos_viewed',
......@@ -30,6 +31,9 @@ class EngagementType(object):
if event_type == ATTEMPTED:
self.name = 'problems_attempted'
self.is_counted_by_entity = True
if event_type == ATTEMPTS_PER_COMPLETED:
self.name = 'problem_attempts_per_completed'
self.is_counted_by_entity = True
if event_type == COMPLETED:
self.name = 'problems_completed'
self.is_counted_by_entity = True
......
......@@ -8,7 +8,7 @@ import random
from django.core.management.base import BaseCommand
from django.utils import timezone
from analytics_data_api.v0 import models
from analytics_data_api.constants import engagement_entity_types, engagement_events
from analytics_data_api.constants import engagement_events
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
......@@ -194,12 +194,13 @@ class Command(BaseCommand):
current = start_date
while current < end_date:
current = current + datetime.timedelta(days=1)
for entity_type in engagement_entity_types.INDIVIDUAL_TYPES:
for event in engagement_events.EVENTS[entity_type]:
for metric in engagement_events.INDIVIDUAL_EVENTS:
num_events = random.randint(0, max_value)
if num_events:
for _ in xrange(num_events):
count = random.randint(0, max_value / 20)
entity_type = metric.split('_', 1)[0]
event = metric.split('_', 1)[1]
entity_id = 'an-id-{}-{}'.format(entity_type, event)
models.ModuleEngagement.objects.create(
course_id=course_id, username=username, date=current,
......@@ -211,18 +212,14 @@ class Command(BaseCommand):
models.ModuleEngagementMetricRanges.objects.all().delete()
logger.info("Generating engagement range data...")
for entity_type in engagement_entity_types.AGGREGATE_TYPES:
for event in engagement_events.EVENTS[entity_type]:
metric = '{0}_{1}'.format(entity_type, event)
for event in engagement_events.EVENTS:
low_ceil = random.random() * max_value * 0.5
models.ModuleEngagementMetricRanges.objects.create(
course_id=course_id, start_date=start_date, end_date=end_date, metric=metric,
course_id=course_id, start_date=start_date, end_date=end_date, metric=event,
range_type='low', low_value=0, high_value=low_ceil)
high_floor = random.random() * max_value * 0.5 + low_ceil
models.ModuleEngagementMetricRanges.objects.create(
course_id=course_id, start_date=start_date, end_date=end_date, metric=metric,
course_id=course_id, start_date=start_date, end_date=end_date, metric=event,
range_type='high', low_value=high_floor, high_value=max_value)
def handle(self, *args, **options):
......
......@@ -3,7 +3,6 @@ from django.conf import settings
from rest_framework import pagination, serializers
from analytics_data_api.constants import (
engagement_entity_types,
engagement_events,
enrollment_modes,
genders,
......@@ -446,14 +445,7 @@ class CourseLearnerMetadataSerializer(serializers.Serializer):
'date_range': DateRangeSerializer(query_set[0] if len(query_set) else None).data
}
# go through each entity and event type combination and fill in the ranges
for entity_type in engagement_entity_types.AGGREGATE_TYPES:
for event in engagement_events.EVENTS[entity_type]:
metric = '{0}_{1}'.format(entity_type, event)
# It's assumed that there may be any combination of low, normal,
# and high ranges in the database for the given course. Some
# edge cases result from a lack of available data; in such
# cases, only some ranges may be returned.
for metric in engagement_events.EVENTS:
low_range_queryset = query_set.filter(metric=metric, range_type='low')
normal_range_queryset = query_set.filter(metric=metric, range_type='normal')
high_range_queryset = query_set.filter(metric=metric, range_type='high')
......
......@@ -9,8 +9,8 @@ import pytz
from rest_framework import status
from analyticsdataserver.tests import TestCaseWithAuthentication
from analytics_data_api.constants.engagement_entity_types import DISCUSSION, PROBLEM, VIDEO
from analytics_data_api.constants.engagement_events import ATTEMPTED, COMPLETED, CONTRIBUTED, VIEWED
from analytics_data_api.constants.engagement_events import (ATTEMPTED, COMPLETED, CONTRIBUTED, DISCUSSION,
PROBLEM, VIDEO, VIEWED)
from analytics_data_api.v0 import models
from analytics_data_api.v0.tests.views import DemoCourseMixin, VerifyCourseIdMixin
......
......@@ -17,7 +17,7 @@ from django.conf import settings
from django.core import management
from analyticsdataserver.tests import TestCaseWithAuthentication
from analytics_data_api.constants import engagement_entity_types, engagement_events
from analytics_data_api.constants import engagement_events
from analytics_data_api.v0.models import ModuleEngagementMetricRanges
from analytics_data_api.v0.tests.views import DemoCourseMixin, VerifyCourseIdMixin
......@@ -571,19 +571,10 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
empty_range = {
range_type: None for range_type in ['below_average', 'average', 'above_average']
}
for metric in self.engagement_metrics:
for metric in engagement_events.EVENTS:
empty_engagement_ranges['engagement_ranges'][metric] = copy.deepcopy(empty_range)
return empty_engagement_ranges
@property
def engagement_metrics(self):
""" Convenience method for getting the metric types. """
metrics = []
for entity_type in engagement_entity_types.AGGREGATE_TYPES:
for event in engagement_events.EVENTS[entity_type]:
metrics.append('{0}_{1}'.format(entity_type, event))
return metrics
def test_no_engagement_ranges(self):
response = self._get(self.course_id)
self.assertEqual(response.status_code, 200)
......@@ -627,7 +618,7 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
}
max_value = 1000.0
for metric_type in self.engagement_metrics:
for metric_type in engagement_events.EVENTS:
low_ceil = 100.5
G(ModuleEngagementMetricRanges, course_id=self.course_id, start_date=start_date, end_date=end_date,
metric=metric_type, range_type='low', low_value=0, high_value=low_ceil)
......@@ -649,12 +640,8 @@ class CourseLearnerMetadataTests(DemoCourseMixin, VerifyCourseIdMixin,
self.assertDictContainsSubset(expected, json.loads(response.content))
def test_engagement_ranges_fields(self):
actual_entity_types = engagement_entity_types.INDIVIDUAL_TYPES
expected_entity_types = ['discussion', 'problem', 'video']
self.assertEqual(actual_entity_types, expected_entity_types)
actual_events = []
for entity_type in actual_entity_types:
for event in engagement_events.EVENTS[entity_type]:
actual_events.append(event)
expected_events = ['contributed', 'attempted', 'attempts_per_completed', 'completed', 'viewed']
self.assertEqual(actual_events, expected_events)
expected_events = engagement_events.EVENTS
response = json.loads(self._get(self.course_id).content)
self.assertTrue('engagement_ranges' in response)
for event in expected_events:
self.assertTrue(event in response['engagement_ranges'])
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