Commit d1019336 by Calen Pennington

Add course tags to all events where a course-id can be extracted from the url

[LMS-2105]
parent 281ad63d
from track.contexts import COURSE_REGEX
from eventtracking import tracker
from user_api.models import UserCourseTag
class UserTagsEventContextMiddleware(object):
CONTEXT_NAME = 'user_tags_context'
def process_request(self, request):
"""
Add a user's tags to the tracking event context.
"""
match = COURSE_REGEX.match(request.build_absolute_uri())
course_id = None
if match:
course_id = match.group('course_id')
context = {}
if course_id:
context['course_id'] = course_id
if request.user.is_authenticated():
context['course_user_tags'] = dict(
UserCourseTag.objects.filter(
user=request.user.pk,
course_id=course_id
).values_list('key', 'value')
)
else:
context['course_user_tags'] = {}
tracker.get_tracker().enter_context(
self.CONTEXT_NAME,
context
)
def process_response(self, request, response): # pylint: disable=unused-argument
"""Exit the context if it exists."""
try:
tracker.get_tracker().exit_context(self.CONTEXT_NAME)
except: # pylint: disable=bare-except
pass
return response
\ No newline at end of file
from factory.django import DjangoModelFactory
from user_api.models import UserPreference
from factory import SubFactory
from student.tests.factories import UserFactory
from user_api.models import UserPreference, UserCourseTag
class UserPreferenceFactory(DjangoModelFactory):
......@@ -8,3 +10,12 @@ class UserPreferenceFactory(DjangoModelFactory):
user = None
key = None
value = "default test value"
class UserCourseTagFactory(DjangoModelFactory):
FACTORY_FOR = UserCourseTag
user = SubFactory(UserFactory)
course_id = 'org/course/run'
key = None
value = None
from mock import Mock, patch
from unittest import TestCase
from django.http import HttpRequest, HttpResponse
from django.test.client import RequestFactory
from student.tests.factories import UserFactory, AnonymousUserFactory
from user_api.tests.factories import UserCourseTagFactory
from user_api.middleware import UserTagsEventContextMiddleware
class TagsMiddlewareTest(TestCase):
"""
Test the UserTagsEventContextMiddleware
"""
def setUp(self):
self.middleware = UserTagsEventContextMiddleware()
self.user = UserFactory.create()
self.other_user = UserFactory.create()
self.course_id = 'mock/course/id'
self.request_factory = RequestFactory()
# TODO: Make it so we can use reverse. Appears to fail depending on the order in which tests are run
#self.request = RequestFactory().get(reverse('courseware', kwargs={'course_id': self.course_id}))
self.request = RequestFactory().get('/courses/{}/courseware'.format(self.course_id))
self.request.user = self.user
self.response = Mock(spec=HttpResponse)
patcher = patch('user_api.middleware.tracker')
self.tracker = patcher.start()
self.addCleanup(patcher.stop)
def process_request(self):
"""
Execute process request using the request, and verify that it returns None
so that the request continues.
"""
# Middleware should pass request through
self.assertEquals(self.middleware.process_request(self.request), None)
def assertContextSetTo(self, context):
self.tracker.get_tracker.return_value.enter_context.assert_called_with(
UserTagsEventContextMiddleware.CONTEXT_NAME,
context
)
def test_tag_context(self):
for key, value in (('int_value', 1), ('str_value', "two")):
UserCourseTagFactory.create(
course_id=self.course_id,
user=self.user,
key=key,
value=value,
)
UserCourseTagFactory.create(
course_id=self.course_id,
user=self.other_user,
key="other_user",
value="other_user_value"
)
UserCourseTagFactory.create(
course_id='other/course/id',
user=self.user,
key="other_course",
value="other_course_value"
)
self.process_request()
self.assertContextSetTo({
'course_id': self.course_id,
'course_user_tags': {
'int_value': '1',
'str_value': 'two',
}
})
def test_no_tags(self):
self.process_request()
self.assertContextSetTo({'course_id': self.course_id, 'course_user_tags': {}})
def test_not_course_url(self):
self.request = self.request_factory.get('/not/a/course/url')
self.request.user = self.user
self.process_request()
self.assertContextSetTo({})
def test_anonymous_user(self):
self.request.user = AnonymousUserFactory()
self.process_request()
self.assertContextSetTo({'course_id': self.course_id, 'course_user_tags': {}})
def test_remove_context(self):
get_tracker = self.tracker.get_tracker
exit_context = get_tracker.return_value.exit_context
# The middleware should clean up the context when the request is done
self.assertEquals(
self.middleware.process_response(self.request, self.response),
self.response
)
exit_context.assert_called_with(UserTagsEventContextMiddleware.CONTEXT_NAME)
exit_context.reset_mock()
# Even if the tracker blows up, the middleware should still return the response
get_tracker.side_effect = Exception
self.assertEquals(
self.middleware.process_response(self.request, self.response),
self.response
)
......@@ -703,6 +703,10 @@ MIDDLEWARE_CLASSES = (
'contentserver.middleware.StaticContentServer',
'crum.CurrentRequestUserMiddleware',
# Adds user tags to tracking events
# Must go before TrackMiddleware, to get the context set up
'user_api.middleware.UserTagsEventContextMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'track.middleware.TrackMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
......
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