From 7d690dde8a9e879c1444d8df832847063f07854f Mon Sep 17 00:00:00 2001 From: Sanford Student Date: Mon, 25 Jul 2016 12:50:02 -0400 Subject: [PATCH] adding request cache for milestones --- common/djangoapps/util/milestones_helpers.py | 58 ++++++++++++-------- lms/djangoapps/gating/api.py | 7 +-- openedx/core/lib/gating/api.py | 1 - 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/common/djangoapps/util/milestones_helpers.py b/common/djangoapps/util/milestones_helpers.py index b30c4a21d9..c4c3b9fe5b 100644 --- a/common/djangoapps/util/milestones_helpers.py +++ b/common/djangoapps/util/milestones_helpers.py @@ -9,13 +9,19 @@ from django.utils.translation import ugettext as _ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey +from milestones import api as milestones_api +from milestones.exceptions import InvalidMilestoneRelationshipTypeException +from milestones.models import MilestoneRelationshipType from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from xmodule.modulestore.django import modulestore +import request_cache NAMESPACE_CHOICES = { 'ENTRANCE_EXAM': 'entrance_exams' } +REQUEST_CACHE_NAME = "milestones" + def get_namespace_choices(): """ @@ -49,7 +55,6 @@ def add_prerequisite_course(course_key, prerequisite_course_key): """ if not is_prerequisite_courses_enabled(): return None - from milestones import api as milestones_api milestone_name = _('Course {course_id} requires {prerequisite_course_id}').format( course_id=unicode(course_key), prerequisite_course_id=unicode(prerequisite_course_key) @@ -73,7 +78,6 @@ def remove_prerequisite_course(course_key, milestone): """ if not is_prerequisite_courses_enabled(): return None - from milestones import api as milestones_api milestones_api.remove_course_milestone( course_key, milestone, @@ -89,7 +93,6 @@ def set_prerequisite_courses(course_key, prerequisite_course_keys): """ if not is_prerequisite_courses_enabled(): return None - from milestones import api as milestones_api #remove any existing requirement milestones with this pre-requisite course as requirement course_milestones = milestones_api.get_course_milestones(course_key=course_key, relationship="requires") if course_milestones: @@ -123,7 +126,6 @@ def get_pre_requisite_courses_not_completed(user, enrolled_courses): # pylint: if not is_prerequisite_courses_enabled(): return {} - from milestones import api as milestones_api pre_requisite_courses = {} for course_key in enrolled_courses: @@ -185,8 +187,6 @@ def fulfill_course_milestone(course_key, user): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api - from milestones.exceptions import InvalidMilestoneRelationshipTypeException try: course_milestones = milestones_api.get_course_milestones(course_key=course_key, relationship="fulfills") except InvalidMilestoneRelationshipTypeException: @@ -203,7 +203,6 @@ def remove_course_milestones(course_key, user, relationship): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api course_milestones = milestones_api.get_course_milestones(course_key=course_key, relationship=relationship) for milestone in course_milestones: milestones_api.remove_user_milestone({'id': user.id}, milestone) @@ -216,7 +215,6 @@ def get_required_content(course, user): """ required_content = [] if settings.FEATURES.get('MILESTONES_APP', False): - from milestones.exceptions import InvalidMilestoneRelationshipTypeException # Get all of the outstanding milestones for this course, for this user try: milestone_paths = get_course_milestones_fulfillment_paths( @@ -241,7 +239,6 @@ def milestones_achieved_by_user(user, namespace): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.get_user_milestones({'id': user.id}, namespace) @@ -262,7 +259,6 @@ def seed_milestone_relationship_types(): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones.models import MilestoneRelationshipType MilestoneRelationshipType.objects.create(name='requires') MilestoneRelationshipType.objects.create(name='fulfills') @@ -291,7 +287,6 @@ def add_milestone(milestone_data): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.add_milestone(milestone_data) @@ -301,7 +296,6 @@ def get_milestones(namespace): """ if not settings.FEATURES.get('MILESTONES_APP', False): return [] - from milestones import api as milestones_api return milestones_api.get_milestones(namespace) @@ -311,7 +305,6 @@ def get_milestone_relationship_types(): """ if not settings.FEATURES.get('MILESTONES_APP', False): return {} - from milestones import api as milestones_api return milestones_api.get_milestone_relationship_types() @@ -321,7 +314,6 @@ def add_course_milestone(course_id, relationship, milestone): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.add_course_milestone(course_id, relationship, milestone) @@ -331,7 +323,6 @@ def get_course_milestones(course_id): """ if not settings.FEATURES.get('MILESTONES_APP', False): return [] - from milestones import api as milestones_api return milestones_api.get_course_milestones(course_id) @@ -341,7 +332,6 @@ def add_course_content_milestone(course_id, content_id, relationship, milestone) """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.add_course_content_milestone(course_id, content_id, relationship, milestone) @@ -351,12 +341,31 @@ def get_course_content_milestones(course_id, content_id, relationship, user_id=N """ if not settings.FEATURES.get('MILESTONES_APP', False): return [] - from milestones import api as milestones_api + + if user_id is None: + return milestones_api.get_course_content_milestones(course_id, content_id, relationship) + + request_cache_dict = request_cache.get_cache(REQUEST_CACHE_NAME) + if user_id not in request_cache_dict: + request_cache_dict[user_id] = milestones_api.get_course_content_milestones( + course_key=course_id, + user={"id": user_id} + ) + milestones_for_content = [] + if relationship == "requires": + for milestone in request_cache_dict[user_id]: + if milestone["content_id"] == content_id and milestone["requirements"]: + milestones_for_content.append(milestone) + if relationship == "fulfills": + for milestone in request_cache_dict[user_id]: + if milestone["namespace"].contains(content_id) and milestone["requirements"]: + milestones_for_content.append(milestone) + return milestones_api.get_course_content_milestones( course_id, content_id, relationship, - {'id': user_id} if user_id else None + user={"id": user_id} ) @@ -366,7 +375,6 @@ def remove_course_content_user_milestones(course_key, content_key, user, relatio """ if not settings.FEATURES.get('MILESTONES_APP', False): return [] - from milestones import api as milestones_api course_content_milestones = milestones_api.get_course_content_milestones(course_key, content_key, relationship) for milestone in course_content_milestones: @@ -379,7 +387,6 @@ def remove_content_references(content_id): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.remove_content_references(content_id) @@ -398,7 +405,6 @@ def get_course_milestones_fulfillment_paths(course_id, user_id): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.get_course_milestones_fulfillment_paths( course_id, user_id @@ -411,5 +417,13 @@ def add_user_milestone(user, milestone): """ if not settings.FEATURES.get('MILESTONES_APP', False): return None - from milestones import api as milestones_api return milestones_api.add_user_milestone(user, milestone) + + +def remove_user_milestone(user, milestone): + """ + Client API operation adapter/wrapper + """ + if not settings.FEATURES.get('MILESTONES_APP', False): + return None + return milestones_api.remove_user_milestone(user, milestone) diff --git a/lms/djangoapps/gating/api.py b/lms/djangoapps/gating/api.py index 4781acf346..416d70d583 100644 --- a/lms/djangoapps/gating/api.py +++ b/lms/djangoapps/gating/api.py @@ -7,10 +7,9 @@ import json from collections import defaultdict from django.contrib.auth.models import User from xmodule.modulestore.django import modulestore -from milestones import api as milestones_api from openedx.core.lib.gating import api as gating_api from lms.djangoapps.grades.module_grades import get_module_score - +from util import milestones_helpers log = logging.getLogger(__name__) @@ -81,6 +80,6 @@ def evaluate_prerequisite(course, prereq_content_key, user_id): ) if score >= min_score: - milestones_api.add_user_milestone({'id': user_id}, prereq_milestone) + milestones_helpers.add_user_milestone({'id': user_id}, prereq_milestone) else: - milestones_api.remove_user_milestone({'id': user_id}, prereq_milestone) + milestones_helpers.remove_user_milestone({'id': user_id}, prereq_milestone) diff --git a/openedx/core/lib/gating/api.py b/openedx/core/lib/gating/api.py index c4acebc1fa..77506444e9 100644 --- a/openedx/core/lib/gating/api.py +++ b/openedx/core/lib/gating/api.py @@ -9,7 +9,6 @@ from opaque_keys.edx.keys import UsageKey from xmodule.modulestore.django import modulestore from openedx.core.lib.gating.exceptions import GatingValidationError - log = logging.getLogger(__name__) # This is used to namespace gating-specific milestones