Add "last completed block" to dropdown
This commit is contained in:
committed by
Sanford Student
parent
335bf4b035
commit
a5d8cbb8e9
@@ -1,11 +1,22 @@
|
||||
""" Unit tests for custom UserProfile properties. """
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
import ddt
|
||||
|
||||
from django.test import TestCase
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from django.test.utils import override_settings
|
||||
from mock import patch
|
||||
|
||||
from ..utils import validate_social_link, format_social_link
|
||||
from completion import models
|
||||
from completion.test_utils import CompletionWaffleTestMixin
|
||||
from openedx.core.djangoapps.user_api.accounts.utils import retrieve_last_sitewide_block_completed
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
|
||||
from ..utils import format_social_link, validate_social_link
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -51,3 +62,77 @@ class UserAccountSettingsTest(TestCase):
|
||||
self.assertEqual(is_valid_expected, self.validate_social_link(platform_name, link_input))
|
||||
|
||||
self.assertEqual(formatted_link_expected, format_social_link(platform_name, link_input))
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class CompletionUtilsTestCase(SharedModuleStoreTestCase, CompletionWaffleTestMixin, TestCase):
|
||||
"""
|
||||
Test completion utility functions
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Creates a test course that can be used for non-destructive tests
|
||||
"""
|
||||
super(CompletionUtilsTestCase, self).setUp()
|
||||
self.override_waffle_switch(True)
|
||||
self.engaged_user = UserFactory.create()
|
||||
self.cruft_user = UserFactory.create()
|
||||
self.course = self.create_test_course()
|
||||
self.submit_faux_completions()
|
||||
|
||||
def create_test_course(self):
|
||||
"""
|
||||
Create, populate test course.
|
||||
"""
|
||||
course = CourseFactory.create()
|
||||
with self.store.bulk_operations(course.id):
|
||||
self.chapter = ItemFactory.create(category='chapter', parent_location=course.location)
|
||||
self.sequential = ItemFactory.create(category='sequential', parent_location=self.chapter.location)
|
||||
self.vertical1 = ItemFactory.create(category='vertical', parent_location=self.sequential.location)
|
||||
self.vertical2 = ItemFactory.create(category='vertical', parent_location=self.sequential.location)
|
||||
course.children = [self.chapter]
|
||||
self.chapter.children = [self.sequential]
|
||||
self.sequential.children = [self.vertical1, self.vertical2]
|
||||
|
||||
if hasattr(self, 'user_one'):
|
||||
CourseEnrollment.enroll(self.engaged_user, course.id)
|
||||
if hasattr(self, 'user_two'):
|
||||
CourseEnrollment.enroll(self.cruft_user, course.id)
|
||||
return course
|
||||
|
||||
def submit_faux_completions(self):
|
||||
"""
|
||||
Submit completions (only for user_one)g
|
||||
"""
|
||||
for block in self.course.children[0].children[0].children:
|
||||
models.BlockCompletion.objects.submit_completion(
|
||||
user=self.engaged_user,
|
||||
course_key=self.course.id,
|
||||
block_key=block.location,
|
||||
completion=1.0
|
||||
)
|
||||
|
||||
@override_settings(LMS_ROOT_URL='test_url:9999')
|
||||
@patch('completion.waffle.get_current_site')
|
||||
@ddt.data(True, False)
|
||||
def test_retrieve_last_sitewide_block_completed(self, use_username, get_patched_current_site): # pylint: disable=unused-argument
|
||||
"""
|
||||
Test that the method returns a URL for the "last completed" block
|
||||
when sending a user object
|
||||
"""
|
||||
block_url = retrieve_last_sitewide_block_completed(
|
||||
self.engaged_user.username if use_username else self.engaged_user
|
||||
)
|
||||
empty_block_url = retrieve_last_sitewide_block_completed(
|
||||
self.cruft_user.username if use_username else self.cruft_user
|
||||
)
|
||||
self.assertEqual(
|
||||
block_url,
|
||||
u'test_url:9999/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/vertical/{vertical_id}'.format(
|
||||
org=self.course.location.course_key.org,
|
||||
course=self.course.location.course_key.course,
|
||||
run=self.course.location.course_key.run,
|
||||
vertical_id=self.vertical2.location.block_id,
|
||||
)
|
||||
)
|
||||
self.assertEqual(empty_block_url, None)
|
||||
|
||||
@@ -5,7 +5,15 @@ import re
|
||||
from urlparse import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import ugettext as _
|
||||
from six import text_type
|
||||
|
||||
from completion import waffle as completion_waffle
|
||||
from completion.models import BlockCompletion
|
||||
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
|
||||
from openedx.core.djangoapps.theming.helpers import get_config_value_from_site_or_settings, get_current_site
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
|
||||
def validate_social_link(platform_name, new_social_link):
|
||||
@@ -89,3 +97,77 @@ def _is_valid_social_username(value):
|
||||
in the username.
|
||||
"""
|
||||
return '/' not in value
|
||||
|
||||
|
||||
def retrieve_last_sitewide_block_completed(username):
|
||||
"""
|
||||
Completion utility
|
||||
From a string 'username' or object User retrieve
|
||||
the last course block marked as 'completed' and construct a URL
|
||||
|
||||
:param username: str(username) or obj(User)
|
||||
:return: block_lms_url
|
||||
|
||||
"""
|
||||
if not completion_waffle.waffle().is_enabled(completion_waffle.ENABLE_COMPLETION_TRACKING):
|
||||
return
|
||||
|
||||
if not isinstance(username, User):
|
||||
userobj = User.objects.get(username=username)
|
||||
else:
|
||||
userobj = username
|
||||
latest_completions_by_course = BlockCompletion.latest_blocks_completed_all_courses(userobj)
|
||||
|
||||
known_site_configs = [
|
||||
other_site_config.get_value('course_org_filter') for other_site_config in SiteConfiguration.objects.all()
|
||||
if other_site_config.get_value('course_org_filter')
|
||||
]
|
||||
|
||||
current_site_configuration = get_config_value_from_site_or_settings(
|
||||
name='course_org_filter',
|
||||
site=get_current_site()
|
||||
)
|
||||
|
||||
# courses.edx.org has no 'course_org_filter'
|
||||
# however the courses within DO, but those entries are not found in
|
||||
# known_site_configs, which are White Label sites
|
||||
# This is necessary because the WL sites and courses.edx.org
|
||||
# have the same AWS RDS mySQL instance
|
||||
candidate_course = None
|
||||
candidate_block_key = None
|
||||
latest_date = None
|
||||
# Go through dict, find latest
|
||||
for course, [modified_date, block_key] in latest_completions_by_course.items():
|
||||
if not current_site_configuration:
|
||||
# This is a edx.org
|
||||
if course.org in known_site_configs:
|
||||
continue
|
||||
if not latest_date or modified_date > latest_date:
|
||||
candidate_course = course
|
||||
candidate_block_key = block_key
|
||||
latest_date = modified_date
|
||||
|
||||
else:
|
||||
# This is a White Label site, and we should find candidates from the same site
|
||||
if course.org not in current_site_configuration:
|
||||
# Not the same White Label, or a edx.org course
|
||||
continue
|
||||
if not latest_date or modified_date > latest_date:
|
||||
candidate_course = course
|
||||
candidate_block_key = block_key
|
||||
latest_date = modified_date
|
||||
|
||||
if not candidate_course:
|
||||
return
|
||||
|
||||
lms_root = SiteConfiguration.get_value_for_org(candidate_course.org, "LMS_ROOT_URL", settings.LMS_ROOT_URL)
|
||||
item = modulestore().get_item(candidate_block_key, depth=1)
|
||||
|
||||
if not lms_root:
|
||||
return
|
||||
|
||||
return u"{lms_root}/courses/{course_key}/jump_to/{location}".format(
|
||||
lms_root=lms_root,
|
||||
course_key=text_type(item.location.course_key),
|
||||
location=text_type(item.location),
|
||||
)
|
||||
|
||||
@@ -10,6 +10,7 @@ from completion.models import BlockCompletion
|
||||
from completion.test_utils import CompletionWaffleTestMixin
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import override_settings
|
||||
from mock import Mock, patch
|
||||
from six import text_type
|
||||
|
||||
@@ -402,6 +403,7 @@ class TestCourseOutlineResumeCourse(SharedModuleStoreTestCase, CompletionWaffleT
|
||||
),
|
||||
active=True
|
||||
)
|
||||
@override_settings(LMS_BASE='test_url:9999')
|
||||
@patch('completion.waffle.get_current_site')
|
||||
def test_resume_course_with_completion_api(self, get_patched_current_site):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user