moving milestones check to access.py
This commit is contained in:
@@ -345,14 +345,19 @@ def add_course_content_milestone(course_id, content_id, relationship, milestone)
|
||||
return milestones_api.add_course_content_milestone(course_id, content_id, relationship, milestone)
|
||||
|
||||
|
||||
def get_course_content_milestones(course_id, content_id, relationship):
|
||||
def get_course_content_milestones(course_id, content_id, relationship, user_id=None):
|
||||
"""
|
||||
Client API operation adapter/wrapper
|
||||
"""
|
||||
if not settings.FEATURES.get('MILESTONES_APP', False):
|
||||
return []
|
||||
from milestones import api as milestones_api
|
||||
return milestones_api.get_course_content_milestones(course_id, content_id, relationship)
|
||||
return milestones_api.get_course_content_milestones(
|
||||
course_id,
|
||||
content_id,
|
||||
relationship,
|
||||
{'id': user_id} if user_id else None
|
||||
)
|
||||
|
||||
|
||||
def remove_course_content_user_milestones(course_key, content_key, user, relationship):
|
||||
|
||||
@@ -20,6 +20,7 @@ from django.utils.timezone import UTC
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
|
||||
from util import milestones_helpers as milestones_helpers
|
||||
from xblock.core import XBlock
|
||||
|
||||
from xmodule.course_module import (
|
||||
@@ -552,19 +553,18 @@ def _has_access_descriptor(user, action, descriptor, course_key=None):
|
||||
students to see modules. If not, views should check the course, so we
|
||||
don't have to hit the enrollments table on every module load.
|
||||
"""
|
||||
response = (
|
||||
_visible_to_nonstaff_users(descriptor)
|
||||
and _has_group_access(descriptor, user, course_key)
|
||||
and
|
||||
(
|
||||
_has_detached_class_tag(descriptor)
|
||||
or _can_access_descriptor_with_start_date(user, descriptor, course_key)
|
||||
)
|
||||
)
|
||||
if _has_staff_access_to_descriptor(user, descriptor, course_key):
|
||||
return ACCESS_GRANTED
|
||||
|
||||
# if the user has staff access, they can load the module so this code doesn't need to run
|
||||
return (
|
||||
ACCESS_GRANTED if (response or _has_staff_access_to_descriptor(user, descriptor, course_key))
|
||||
else response
|
||||
_visible_to_nonstaff_users(descriptor) and
|
||||
_can_access_descriptor_with_milestones(user, descriptor, course_key) and
|
||||
_has_group_access(descriptor, user, course_key) and
|
||||
(
|
||||
_has_detached_class_tag(descriptor) or
|
||||
_can_access_descriptor_with_start_date(user, descriptor, course_key)
|
||||
)
|
||||
)
|
||||
|
||||
checkers = {
|
||||
@@ -801,6 +801,22 @@ def _visible_to_nonstaff_users(descriptor):
|
||||
return VisibilityError() if descriptor.visible_to_staff_only else ACCESS_GRANTED
|
||||
|
||||
|
||||
def _can_access_descriptor_with_milestones(user, descriptor, course_key):
|
||||
"""
|
||||
Returns if the object is blocked by an unfulfilled milestone.
|
||||
|
||||
Args:
|
||||
user: the user trying to access this content
|
||||
descriptor: the object being accessed
|
||||
course_key: key for the course for this descriptor
|
||||
"""
|
||||
if milestones_helpers.get_course_content_milestones(course_key, descriptor.location, 'requires', user.id):
|
||||
debug("Deny: user has not completed all milestones for content")
|
||||
return ACCESS_DENIED
|
||||
else:
|
||||
return ACCESS_GRANTED
|
||||
|
||||
|
||||
def _has_detached_class_tag(descriptor):
|
||||
"""
|
||||
Returns if the given descriptor's type is marked as detached.
|
||||
|
||||
@@ -17,7 +17,6 @@ from opaque_keys.edx.keys import CourseKey
|
||||
from opaque_keys.edx.locator import BlockUsageLocator
|
||||
from openedx.core.djangoapps.content.block_structure.api import get_course_in_cache
|
||||
from openedx.core.lib.cache_utils import memoized
|
||||
from openedx.core.lib.gating import api as gating_api
|
||||
from courseware.model_data import FieldDataCache, ScoresClient
|
||||
from openedx.core.djangoapps.signals.signals import GRADES_UPDATED
|
||||
from student.models import anonymous_id_for_user
|
||||
@@ -513,9 +512,6 @@ def _progress_summary(student, course, course_structure=None):
|
||||
unicode(course.id), anonymous_id_for_user(student, course.id)
|
||||
)
|
||||
|
||||
# Check for gated content
|
||||
gated_content = gating_api.get_gated_content(course, student)
|
||||
|
||||
chapters = []
|
||||
locations_to_weighted_scores = {}
|
||||
|
||||
@@ -523,9 +519,6 @@ def _progress_summary(student, course, course_structure=None):
|
||||
chapter = course_structure[chapter_key]
|
||||
sections = []
|
||||
for section_key in course_structure.get_children(chapter_key):
|
||||
if unicode(section_key) in gated_content:
|
||||
continue
|
||||
|
||||
section = course_structure[section_key]
|
||||
|
||||
graded = getattr(section, 'graded', False)
|
||||
|
||||
@@ -32,7 +32,6 @@ from xblock.exceptions import NoSuchHandlerError, NoSuchViewError
|
||||
from xblock.reference.plugins import FSService
|
||||
|
||||
import static_replace
|
||||
from openedx.core.lib.gating import api as gating_api
|
||||
from courseware.access import has_access, get_user_role
|
||||
from courseware.entrance_exams import (
|
||||
get_entrance_exam_score,
|
||||
@@ -164,9 +163,6 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
|
||||
# before the rest of the content is made available
|
||||
required_content = milestones_helpers.get_required_content(course, user)
|
||||
|
||||
# Check for gated content
|
||||
gated_content = gating_api.get_gated_content(course, user)
|
||||
|
||||
# The user may not actually have to complete the entrance exam, if one is required
|
||||
if not user_must_complete_entrance_exam(request, user, course):
|
||||
required_content = [content for content in required_content if not content == course.entrance_exam_id]
|
||||
@@ -189,9 +185,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
|
||||
|
||||
sections = list()
|
||||
for section in chapter.get_display_items():
|
||||
# skip the section if it is gated/hidden from the user
|
||||
if gated_content and unicode(section.location) in gated_content:
|
||||
continue
|
||||
# skip the section if it is hidden from the user
|
||||
if section.hide_from_toc:
|
||||
continue
|
||||
|
||||
|
||||
@@ -1111,6 +1111,7 @@ class TestGatedSubsectionRendering(SharedModuleStoreTestCase, MilestonesTestCase
|
||||
|
||||
return None
|
||||
|
||||
@patch.dict(settings.FEATURES, {'MILESTONES_APP': True})
|
||||
def test_toc_with_gated_sequential(self):
|
||||
"""
|
||||
Test generation of TOC for a course with a gated subsection
|
||||
|
||||
@@ -1787,7 +1787,7 @@ class TestIndexView(ModuleStoreTestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestIndewViewWithVerticalPositions(ModuleStoreTestCase):
|
||||
class TestIndexViewWithVerticalPositions(ModuleStoreTestCase):
|
||||
"""
|
||||
Test the index view to handle vertical positions. Confirms that first position is loaded
|
||||
if input position is non-positive or greater than number of positions available.
|
||||
@@ -1797,7 +1797,7 @@ class TestIndewViewWithVerticalPositions(ModuleStoreTestCase):
|
||||
"""
|
||||
Set up initial test data
|
||||
"""
|
||||
super(TestIndewViewWithVerticalPositions, self).setUp()
|
||||
super(TestIndexViewWithVerticalPositions, self).setUp()
|
||||
|
||||
self.user = UserFactory()
|
||||
|
||||
@@ -1875,6 +1875,7 @@ class TestIndexViewWithGating(ModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
|
||||
CourseEnrollmentFactory(user=self.user, course_id=self.course.id)
|
||||
|
||||
@patch.dict(settings.FEATURES, {'MILESTONES_APP': True})
|
||||
def test_index_with_gated_sequential(self):
|
||||
"""
|
||||
Test index view with a gated sequential raises Http404
|
||||
|
||||
@@ -25,7 +25,6 @@ import urllib
|
||||
from lang_pref import LANGUAGE_KEY
|
||||
from xblock.fragment import Fragment
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.lib.gating import api as gating_api
|
||||
from openedx.core.lib.time_zone_utils import get_user_time_zone
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
from shoppingcart.models import CourseRegistrationCode
|
||||
@@ -143,7 +142,6 @@ class CoursewareIndex(View):
|
||||
|
||||
if self.chapter and self.section:
|
||||
self._redirect_if_not_requested_section()
|
||||
self._verify_section_not_gated()
|
||||
self._save_positions()
|
||||
self._prefetch_and_bind_section()
|
||||
|
||||
@@ -272,15 +270,6 @@ class CoursewareIndex(View):
|
||||
self.chapter_url_name = exam_chapter.url_name
|
||||
self.section_url_name = exam_section.url_name
|
||||
|
||||
def _verify_section_not_gated(self):
|
||||
"""
|
||||
Verify whether the section is gated and accessible to the user.
|
||||
"""
|
||||
gated_content = gating_api.get_gated_content(self.course, self.effective_user)
|
||||
if gated_content:
|
||||
if unicode(self.section.location) in gated_content:
|
||||
raise Http404
|
||||
|
||||
def _get_language_preference(self):
|
||||
"""
|
||||
Returns the preferred language for the actual user making the request.
|
||||
|
||||
Reference in New Issue
Block a user