Commit 136f3d34 by Bill DeRusha

Merge pull request #12552 from edx/release

Merge Release 2016-05-24 to Master
parents 025f74c8 14c02628
......@@ -8,7 +8,7 @@ from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.django import modulestore
from ...api import get_course_in_cache
from ...api import get_course_in_cache, update_course_in_cache
log = logging.getLogger(__name__)
......@@ -39,6 +39,12 @@ class Command(BaseCommand):
action='store_true',
default=False,
)
parser.add_argument(
'--force',
help='Force update of the course blocks for the requested courses.',
action='store_true',
default=False,
)
def handle(self, *args, **options):
......@@ -57,7 +63,10 @@ class Command(BaseCommand):
for course_key in course_keys:
try:
block_structure = get_course_in_cache(course_key)
if options.get('force'):
block_structure = update_course_in_cache(course_key)
else:
block_structure = get_course_in_cache(course_key)
if options.get('dags'):
self._find_and_log_dags(block_structure, course_key)
except Exception as ex: # pylint: disable=broad-except
......
......@@ -44,6 +44,21 @@ class TestGenerateCourseBlocks(ModuleStoreTestCase):
self._assert_courses_not_in_block_cache(self.course_1.id, self.course_2.id)
self.command.handle(all=True)
self._assert_courses_in_block_cache(self.course_1.id, self.course_2.id)
with patch(
'openedx.core.lib.block_structure.factory.BlockStructureFactory.create_from_modulestore'
) as mock_update_from_store:
self.command.handle(all=True)
mock_update_from_store.assert_not_called()
def test_generate_force(self):
self._assert_courses_not_in_block_cache(self.course_1.id, self.course_2.id)
self.command.handle(all=True)
self._assert_courses_in_block_cache(self.course_1.id, self.course_2.id)
with patch(
'openedx.core.lib.block_structure.factory.BlockStructureFactory.create_from_modulestore'
) as mock_update_from_store:
self.command.handle(all=True, force=True)
mock_update_from_store.assert_called()
def test_generate_one(self):
self._assert_courses_not_in_block_cache(self.course_1.id, self.course_2.id)
......
......@@ -111,7 +111,7 @@ class DateSummary(object):
date_format = _(u"{relative} ago - {absolute}") if date_has_passed else _(u"in {relative} - {absolute}")
return date_format.format(
relative=relative_date,
absolute=self.date.strftime(self.date_format),
absolute=self.date.strftime(self.date_format.encode('utf-8')).decode('utf-8'),
)
@property
......@@ -157,7 +157,9 @@ class TodaysDate(DateSummary):
@property
def title(self):
return _(u'Today is {date}').format(date=datetime.now(pytz.UTC).strftime(self.date_format))
return _(u'Today is {date}').format(
date=datetime.now(pytz.UTC).strftime(self.date_format.encode('utf-8')).decode('utf-8')
)
class CourseStartDate(DateSummary):
......
""" Course Discovery API Service. """
from django.conf import settings
import datetime
from django.conf import settings
from edx_rest_api_client.client import EdxRestApiClient
import jwt
from openedx.core.djangoapps.theming import helpers
from openedx.core.lib.token_utils import get_id_token
from provider.oauth2.models import Client
from student.models import UserProfile, anonymous_id_for_user
CLIENT_NAME = 'course-discovery'
def get_id_token(user):
"""
Return a JWT for `user`, suitable for use with the course discovery service.
Arguments:
user (User): User for whom to generate the JWT.
Returns:
str: The JWT.
"""
try:
# Service users may not have user profiles.
full_name = UserProfile.objects.get(user=user).name
except UserProfile.DoesNotExist:
full_name = None
now = datetime.datetime.utcnow()
expires_in = getattr(settings, 'OAUTH_ID_TOKEN_EXPIRATION', 30)
payload = {
'preferred_username': user.username,
'name': full_name,
'email': user.email,
'administrator': user.is_staff,
'iss': helpers.get_value('OAUTH_OIDC_ISSUER', settings.OAUTH_OIDC_ISSUER),
'exp': now + datetime.timedelta(seconds=expires_in),
'iat': now,
'aud': helpers.get_value('JWT_AUTH', settings.JWT_AUTH)['JWT_AUDIENCE'],
'sub': anonymous_id_for_user(user, None),
}
secret_key = helpers.get_value('JWT_AUTH', settings.JWT_AUTH)['JWT_SECRET_KEY']
return jwt.encode(payload, secret_key)
def course_discovery_api_client(user):
""" Returns a Course Discovery API client setup with authentication for the specified user. """
course_discovery_client = Client.objects.get(name=CLIENT_NAME)
secret_key = helpers.get_value('JWT_AUTH', settings.JWT_AUTH)['JWT_SECRET_KEY']
return EdxRestApiClient(
course_discovery_client.url,
jwt=get_id_token(user, CLIENT_NAME, secret_key=secret_key)
)
return EdxRestApiClient(course_discovery_client.url, jwt=get_id_token(user))
......@@ -96,3 +96,13 @@ def update_course_structure(course_key):
structure_model.structure_json = structure_json
structure_model.discussion_id_map_json = discussion_id_map_json
structure_model.save()
# TODO (TNL-4630) For temporary hotfix to update the block_structure cache.
# Should be moved to proper location.
from django.core.cache import cache
from openedx.core.lib.block_structure.manager import BlockStructureManager
store = modulestore()
course_usage_key = store.make_course_usage_key(course_key)
block_structure_manager = BlockStructureManager(course_usage_key, store, cache)
block_structure_manager.update_collected()
......@@ -45,13 +45,13 @@ class BlockStructureCache(object):
)
zp_data_to_cache = zpickle(data_to_cache)
# Set the timeout value for the cache to None. This caches the
# value forever. The expectation is that the caller will delete
# the cached value once it is outdated.
# Set the timeout value for the cache to 1 day as a fail-safe
# in case the signal to invalidate the cache doesn't come through.
timeout_in_seconds = 60 * 60 * 24
self._cache.set(
self._encode_root_cache_key(block_structure.root_block_usage_key),
zp_data_to_cache,
timeout=None,
timeout=timeout_in_seconds,
)
logger.info(
......
......@@ -36,7 +36,7 @@ class TestBlockStructureCache(ChildrenMapTestMixin, TestCase):
self.add_transformers()
self.block_structure_cache.add(self.block_structure)
self.assertEquals(self.mock_cache.timeout_from_last_call, None)
self.assertEquals(self.mock_cache.timeout_from_last_call, 60 * 60 * 24)
cached_value = self.block_structure_cache.get(self.block_structure.root_block_usage_key)
self.assertIsNotNone(cached_value)
......
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