From fc943ff539fde6a07e58dccf72ea1289b9250c22 Mon Sep 17 00:00:00 2001
From: Sanford Student <sanfordstudent@C02QJ0RCG8WM.tld>
Date: Fri, 29 Jul 2016 09:33:00 -0400
Subject: [PATCH] moving milestones check to access.py and upgrading milestones
 version

---
 .../tests/test_course_settings.py             |  6 +--
 .../student/tests/test_course_listing.py      |  2 +-
 common/djangoapps/util/milestones_helpers.py  |  2 +-
 .../util/tests/test_milestones_helpers.py     |  5 ++-
 lms/djangoapps/branding/tests/test_page.py    |  2 +-
 lms/djangoapps/certificates/tests/tests.py    |  2 +-
 .../course_api/blocks/tests/test_api.py       |  3 +-
 .../course_api/blocks/tests/test_views.py     |  3 +-
 .../transformers/tests/test_milestones.py     |  2 +-
 lms/djangoapps/courseware/access.py           | 38 +++++++++++++------
 lms/djangoapps/courseware/features/common.py  |  7 ----
 lms/djangoapps/courseware/module_render.py    |  8 +---
 lms/djangoapps/courseware/tests/test_about.py |  4 +-
 .../courseware/tests/test_access.py           |  9 ++---
 .../tests/test_discussion_xblock.py           |  3 +-
 .../courseware/tests/test_entrance_exam.py    |  4 +-
 .../courseware/tests/test_masquerade.py       |  3 +-
 .../courseware/tests/test_module_render.py    |  2 +-
 .../courseware/tests/test_navigation.py       |  3 +-
 .../courseware/tests/test_split_module.py     |  3 +-
 lms/djangoapps/courseware/tests/test_tabs.py  |  4 +-
 lms/djangoapps/courseware/tests/test_views.py |  8 ++--
 lms/djangoapps/courseware/views/index.py      | 11 ------
 lms/djangoapps/gating/tests/test_api.py       | 11 ------
 lms/djangoapps/instructor/tests/test_api.py   |  7 +---
 .../mobile_api/tests/test_milestones.py       | 31 +++------------
 lms/djangoapps/mobile_api/users/tests.py      |  1 -
 .../mobile_api/video_outlines/tests.py        |  1 -
 openedx/core/lib/gating/tests/test_api.py     |  1 -
 openedx/tests/xblock_integration/test_done.py |  4 --
 requirements/edx/github.txt                   |  2 +-
 31 files changed, 68 insertions(+), 124 deletions(-)

diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py
index 12ec1dee5de..1efcb8a3936 100644
--- a/cms/djangoapps/contentstore/tests/test_course_settings.py
+++ b/cms/djangoapps/contentstore/tests/test_course_settings.py
@@ -167,13 +167,13 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
         elif field in encoded and encoded[field] is not None:
             self.fail(field + " included in encoding but missing from details at " + context)
 
-    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True})
     def test_pre_requisite_course_list_present(self):
         settings_details_url = get_url(self.course.id)
         response = self.client.get_html(settings_details_url)
         self.assertContains(response, "Prerequisite Course")
 
-    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True})
     def test_pre_requisite_course_update_and_fetch(self):
         url = get_url(self.course.id)
         resp = self.client.get_json(url)
@@ -200,7 +200,7 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin):
         course_detail_json = json.loads(resp.content)
         self.assertEqual([], course_detail_json['pre_requisite_courses'])
 
-    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True})
     def test_invalid_pre_requisite_course(self):
         url = get_url(self.course.id)
         resp = self.client.get_json(url)
diff --git a/common/djangoapps/student/tests/test_course_listing.py b/common/djangoapps/student/tests/test_course_listing.py
index 838aea84289..1a06f7e039d 100644
--- a/common/djangoapps/student/tests/test_course_listing.py
+++ b/common/djangoapps/student/tests/test_course_listing.py
@@ -119,7 +119,7 @@ class TestCourseListing(ModuleStoreTestCase, MilestonesTestCaseMixin):
         self.assertEqual(len(courses_list), 1, courses_list)
         self.assertEqual(courses_list[0].course_id, good_location)
 
-    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True})
     def test_course_listing_has_pre_requisite_courses(self):
         """
         Creates four courses. Enroll test user in all courses
diff --git a/common/djangoapps/util/milestones_helpers.py b/common/djangoapps/util/milestones_helpers.py
index c5648c9242c..b4bb71ff509 100644
--- a/common/djangoapps/util/milestones_helpers.py
+++ b/common/djangoapps/util/milestones_helpers.py
@@ -357,7 +357,7 @@ def get_course_content_milestones(course_id, content_id, relationship, user_id=N
             user={"id": user_id}
         )
 
-    return [m for m in request_cache_dict[user_id][relationship] if m['content_id'] == content_id]
+    return [m for m in request_cache_dict[user_id][relationship] if m['content_id'] == unicode(content_id)]
 
 
 def remove_course_content_user_milestones(course_key, content_key, user, relationship):
diff --git a/common/djangoapps/util/tests/test_milestones_helpers.py b/common/djangoapps/util/tests/test_milestones_helpers.py
index 92b6772193b..c614e2d9a13 100644
--- a/common/djangoapps/util/tests/test_milestones_helpers.py
+++ b/common/djangoapps/util/tests/test_milestones_helpers.py
@@ -117,7 +117,10 @@ class MilestonesHelpersTestCase(ModuleStoreTestCase):
 
     @patch.dict('django.conf.settings.FEATURES', {'MILESTONES_APP': True})
     def test_any_unfulfilled_milestones(self):
-        """ Tests any_unfulfilled_milestones for invalid arguments """
+        """
+        Tests any_unfulfilled_milestones for invalid arguments with
+        the app enabled
+         """
         with self.assertRaises(InvalidCourseKeyException):
             milestones_helpers.any_unfulfilled_milestones(None, self.user)
         with self.assertRaises(InvalidUserException):
diff --git a/lms/djangoapps/branding/tests/test_page.py b/lms/djangoapps/branding/tests/test_page.py
index 247c4d13322..230eec9f694 100644
--- a/lms/djangoapps/branding/tests/test_page.py
+++ b/lms/djangoapps/branding/tests/test_page.py
@@ -118,7 +118,7 @@ class PreRequisiteCourseCatalog(ModuleStoreTestCase, LoginEnrollmentTestCase, Mi
     Test to simulate and verify fix for disappearing courses in
     course catalog when using pre-requisite courses
     """
-    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True})
     def test_course_with_prereq(self):
         """
         Simulate having a course which has closed enrollments that has
diff --git a/lms/djangoapps/certificates/tests/tests.py b/lms/djangoapps/certificates/tests/tests.py
index cb65f8140e0..457b9c53d51 100644
--- a/lms/djangoapps/certificates/tests/tests.py
+++ b/lms/djangoapps/certificates/tests/tests.py
@@ -91,7 +91,7 @@ class CertificatesModelTest(ModuleStoreTestCase, MilestonesTestCaseMixin):
         certificate_info = certificate_info_for_user(student, course.id, grade, whitelisted)
         self.assertEqual(certificate_info, output)
 
-    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True})
     def test_course_milestone_collected(self):
         student = UserFactory()
         course = CourseFactory.create(org='edx', number='998', display_name='Test Course')
diff --git a/lms/djangoapps/course_api/blocks/tests/test_api.py b/lms/djangoapps/course_api/blocks/tests/test_api.py
index 97055cf5d75..f4e3d8688dd 100644
--- a/lms/djangoapps/course_api/blocks/tests/test_api.py
+++ b/lms/djangoapps/course_api/blocks/tests/test_api.py
@@ -4,7 +4,6 @@ Tests for Blocks api.py
 
 from django.test.client import RequestFactory
 
-from milestones.tests.utils import MilestonesTestCaseMixin
 from student.tests.factories import UserFactory
 from xmodule.modulestore import ModuleStoreEnum
 from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
@@ -13,7 +12,7 @@ from xmodule.modulestore.tests.factories import SampleCourseFactory
 from ..api import get_blocks
 
 
-class TestGetBlocks(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
+class TestGetBlocks(SharedModuleStoreTestCase):
     """
     Tests for the get_blocks function
     """
diff --git a/lms/djangoapps/course_api/blocks/tests/test_views.py b/lms/djangoapps/course_api/blocks/tests/test_views.py
index d252ef2fec1..f8d2e2bf161 100644
--- a/lms/djangoapps/course_api/blocks/tests/test_views.py
+++ b/lms/djangoapps/course_api/blocks/tests/test_views.py
@@ -8,7 +8,6 @@ from string import join
 from urllib import urlencode
 from urlparse import urlunparse
 
-from milestones.tests.utils import MilestonesTestCaseMixin
 from opaque_keys.edx.locator import CourseLocator
 from student.models import CourseEnrollment
 from student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
@@ -18,7 +17,7 @@ from xmodule.modulestore.tests.factories import ToyCourseFactory
 from .helpers import deserialize_usage_key
 
 
-class TestBlocksView(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
+class TestBlocksView(SharedModuleStoreTestCase):
     """
     Test class for BlocksView
     """
diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py
index 5e1fd4e960c..5f88c8004e5 100644
--- a/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py
+++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py
@@ -18,7 +18,7 @@ from ...api import get_course_blocks
 
 @attr(shard=3)
 @ddt.ddt
-@patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True, 'MILESTONES_APP': True})
+@patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True})
 class MilestonesTransformerTestCase(CourseStructureTestCase, MilestonesTestCaseMixin):
     """
     Test behavior of ProctoredExamTransformer
diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py
index e6063dbdf5e..d458403f748 100644
--- a/lms/djangoapps/courseware/access.py
+++ b/lms/djangoapps/courseware/access.py
@@ -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, unicode(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.
diff --git a/lms/djangoapps/courseware/features/common.py b/lms/djangoapps/courseware/features/common.py
index cda31091491..79df764fdd8 100644
--- a/lms/djangoapps/courseware/features/common.py
+++ b/lms/djangoapps/courseware/features/common.py
@@ -9,7 +9,6 @@ from lettuce import world, step, before
 from lettuce.django import django_url
 from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse
-from milestones.models import MilestoneRelationshipType
 from student.models import CourseEnrollment
 from xmodule.modulestore.django import modulestore
 from xmodule.course_module import CourseDescriptor
@@ -19,12 +18,6 @@ from logging import getLogger
 logger = getLogger(__name__)
 
 
-@before.each_scenario  # pylint: disable=no-member
-def setup_milestones_app(scenario):  # pylint: disable=unused-argument
-    MilestoneRelationshipType.objects.get_or_create(name='requires')
-    MilestoneRelationshipType.objects.get_or_create(name='fulfills')
-
-
 @step('I (.*) capturing of screenshots before and after each step$')
 def configure_screenshots_for_all_steps(_step, action):
     """
diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py
index e36af37f88b..6b1cf3c3f45 100644
--- a/lms/djangoapps/courseware/module_render.py
+++ b/lms/djangoapps/courseware/module_render.py
@@ -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
 
diff --git a/lms/djangoapps/courseware/tests/test_about.py b/lms/djangoapps/courseware/tests/test_about.py
index 0b733ad20e5..38edb3847a1 100644
--- a/lms/djangoapps/courseware/tests/test_about.py
+++ b/lms/djangoapps/courseware/tests/test_about.py
@@ -140,7 +140,7 @@ class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTra
         info_url = reverse('info', args=[self.course.id.to_deprecated_string()])
         self.assertTrue(target_url.endswith(info_url))
 
-    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True})
     def test_pre_requisite_course(self):
         pre_requisite_course = CourseFactory.create(org='edX', course='900', display_name='pre requisite course')
         course = CourseFactory.create(pre_requisite_courses=[unicode(pre_requisite_course.id)])
@@ -154,7 +154,7 @@ class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTra
                       .format(pre_requisite_course_about_url, pre_requisite_courses[0]['display']),
                       resp.content.strip('\n'))
 
-    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True})
     def test_about_page_unfulfilled_prereqs(self):
         pre_requisite_course = CourseFactory.create(
             org='edX',
diff --git a/lms/djangoapps/courseware/tests/test_access.py b/lms/djangoapps/courseware/tests/test_access.py
index cbbfc5bdb0e..9dcdecd0ef9 100644
--- a/lms/djangoapps/courseware/tests/test_access.py
+++ b/lms/djangoapps/courseware/tests/test_access.py
@@ -166,8 +166,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
 
     def verify_access(self, mock_unit, student_should_have_access, expected_error_type=None):
         """ Verify the expected result from _has_access_descriptor """
-        response = access._has_access_descriptor(self.anonymous_user, 'load',
-                                                 mock_unit, course_key=self.course.id)
+        response = access._has_access_descriptor(self.anonymous_user, 'load', mock_unit, course_key=self.course.id)
         self.assertEqual(student_should_have_access, bool(response))
 
         if expected_error_type is not None:
@@ -383,7 +382,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
         Tests that "visible_to_staff_only" overrides start date.
         """
         expected_access = expected_error_type is None
-        mock_unit = Mock(user_partitions=[])
+        mock_unit = Mock(location=self.course.location, user_partitions=[])
         mock_unit._class_tags = {}  # Needed for detached check in _has_access_descriptor
         mock_unit.visible_to_staff_only = visible_to_staff_only
         mock_unit.start = start
@@ -406,7 +405,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
         """
         Tests that descriptor has access in preview mode.
         """
-        mock_unit = Mock(user_partitions=[])
+        mock_unit = Mock(location=self.course.location, user_partitions=[])
         mock_unit._class_tags = {}  # Needed for detached check in _has_access_descriptor
         mock_unit.visible_to_staff_only = False
         mock_unit.start = start
@@ -425,7 +424,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
         Tests that descriptor has no access when start date in future & without preview.
         """
         expected_access = expected_error_type is None
-        mock_unit = Mock(user_partitions=[])
+        mock_unit = Mock(location=self.course.location, user_partitions=[])
         mock_unit._class_tags = {}  # Needed for detached check in _has_access_descriptor
         mock_unit.visible_to_staff_only = False
         mock_unit.start = start
diff --git a/lms/djangoapps/courseware/tests/test_discussion_xblock.py b/lms/djangoapps/courseware/tests/test_discussion_xblock.py
index d245cdbc31c..34ca9bd4064 100644
--- a/lms/djangoapps/courseware/tests/test_discussion_xblock.py
+++ b/lms/djangoapps/courseware/tests/test_discussion_xblock.py
@@ -15,7 +15,6 @@ import mock
 from django.core.urlresolvers import reverse
 from course_api.blocks.tests.helpers import deserialize_usage_key
 from courseware.module_render import get_module_for_descriptor_internal
-from milestones.tests.utils import MilestonesTestCaseMixin
 from student.tests.factories import UserFactory, CourseEnrollmentFactory
 from xblock.field_data import DictFieldData
 from xblock.fragment import Fragment
@@ -253,7 +252,7 @@ class TestTemplates(TestDiscussionXBlock):
 
 
 @ddt.ddt
-class TestXBlockInCourse(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
+class TestXBlockInCourse(SharedModuleStoreTestCase):
     """
     Test the discussion xblock as rendered in the course and course API.
     """
diff --git a/lms/djangoapps/courseware/tests/test_entrance_exam.py b/lms/djangoapps/courseware/tests/test_entrance_exam.py
index 61963a6dbfc..a14bd2d58e2 100644
--- a/lms/djangoapps/courseware/tests/test_entrance_exam.py
+++ b/lms/djangoapps/courseware/tests/test_entrance_exam.py
@@ -39,7 +39,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
 
 
 @attr(shard=2)
-@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True, 'MILESTONES_APP': True})
+@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True})
 class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTestCaseMixin):
     """
     Check that content is properly gated.
@@ -47,7 +47,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest
     Creates a test course from scratch. The tests below are designed to execute
     workflows regardless of the feature flag settings.
     """
-    @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True, 'MILESTONES_APP': True})
+    @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True})
     def setUp(self):
         """
         Test case scaffolding
diff --git a/lms/djangoapps/courseware/tests/test_masquerade.py b/lms/djangoapps/courseware/tests/test_masquerade.py
index 1efa0a49f2b..39a2a575816 100644
--- a/lms/djangoapps/courseware/tests/test_masquerade.py
+++ b/lms/djangoapps/courseware/tests/test_masquerade.py
@@ -22,7 +22,6 @@ from courseware.masquerade import (
 from courseware.tests.factories import StaffFactory
 from courseware.tests.helpers import LoginEnrollmentTestCase, get_request_for_user
 from courseware.tests.test_submitting_problems import ProblemSubmissionTestMixin
-from milestones.tests.utils import MilestonesTestCaseMixin
 from student.tests.factories import UserFactory
 from xblock.runtime import DictKeyValueStore
 from xmodule.modulestore.django import modulestore
@@ -32,7 +31,7 @@ from xmodule.partitions.partitions import Group, UserPartition
 from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
 
 
-class MasqueradeTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase, MilestonesTestCaseMixin):
+class MasqueradeTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
     """
     Base class for masquerade tests that sets up a test course and enrolls a user in the course.
     """
diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py
index 8cf1115b224..f7cf6ef35fc 100644
--- a/lms/djangoapps/courseware/tests/test_module_render.py
+++ b/lms/djangoapps/courseware/tests/test_module_render.py
@@ -407,7 +407,7 @@ class ModuleRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
 
 
 @attr(shard=1)
-class TestHandleXBlockCallback(SharedModuleStoreTestCase, LoginEnrollmentTestCase, MilestonesTestCaseMixin):
+class TestHandleXBlockCallback(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
     """
     Test the handle_xblock_callback function
     """
diff --git a/lms/djangoapps/courseware/tests/test_navigation.py b/lms/djangoapps/courseware/tests/test_navigation.py
index 53b883fb832..4be076b55d2 100644
--- a/lms/djangoapps/courseware/tests/test_navigation.py
+++ b/lms/djangoapps/courseware/tests/test_navigation.py
@@ -11,7 +11,6 @@ from django.test.utils import override_settings
 
 from courseware.tests.helpers import LoginEnrollmentTestCase
 from courseware.tests.factories import GlobalStaffFactory
-from milestones.tests.utils import MilestonesTestCaseMixin
 from student.tests.factories import UserFactory
 from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
 from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@@ -19,7 +18,7 @@ from xmodule.modulestore.django import modulestore
 
 
 @attr(shard=1)
-class TestNavigation(SharedModuleStoreTestCase, LoginEnrollmentTestCase, MilestonesTestCaseMixin):
+class TestNavigation(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
     """
     Check that navigation state is saved properly.
     """
diff --git a/lms/djangoapps/courseware/tests/test_split_module.py b/lms/djangoapps/courseware/tests/test_split_module.py
index 83782e4f6b4..a8a68f12dd3 100644
--- a/lms/djangoapps/courseware/tests/test_split_module.py
+++ b/lms/djangoapps/courseware/tests/test_split_module.py
@@ -7,7 +7,6 @@ from nose.plugins.attrib import attr
 
 from courseware.module_render import get_module_for_descriptor
 from courseware.model_data import FieldDataCache
-from milestones.tests.utils import MilestonesTestCaseMixin
 from student.tests.factories import UserFactory, CourseEnrollmentFactory
 from xmodule.modulestore.tests.factories import ItemFactory, CourseFactory
 from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
@@ -16,7 +15,7 @@ from openedx.core.djangoapps.user_api.tests.factories import UserCourseTagFactor
 
 
 @attr(shard=1)
-class SplitTestBase(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
+class SplitTestBase(SharedModuleStoreTestCase):
     """
     Sets up a basic course and user for split test testing.
     Also provides tests of rendered HTML for two user_tag conditions, 0 and 1.
diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py
index a818d540046..692b5311fae 100644
--- a/lms/djangoapps/courseware/tests/test_tabs.py
+++ b/lms/djangoapps/courseware/tests/test_tabs.py
@@ -330,14 +330,14 @@ class StaticTabDateTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase):
 
 
 @attr(shard=1)
-@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True, 'MILESTONES_APP': True})
+@patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True})
 class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTestCaseMixin):
     """
     Validate tab behavior when dealing with Entrance Exams
     """
     MODULESTORE = TEST_DATA_MIXED_MODULESTORE
 
-    @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True, 'MILESTONES_APP': True})
+    @patch.dict('django.conf.settings.FEATURES', {'ENTRANCE_EXAMS': True})
     def setUp(self):
         """
         Test case scaffolding
diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py
index fc4536a9fa9..51b2e009dfa 100644
--- a/lms/djangoapps/courseware/tests/test_views.py
+++ b/lms/djangoapps/courseware/tests/test_views.py
@@ -191,7 +191,7 @@ class TestJumpTo(ModuleStoreTestCase):
 
 @attr(shard=2)
 @ddt.ddt
-class ViewsTestCase(ModuleStoreTestCase, MilestonesTestCaseMixin):
+class ViewsTestCase(ModuleStoreTestCase):
     """
     Tests for views.py methods.
     """
@@ -939,7 +939,7 @@ class ViewsTestCase(ModuleStoreTestCase, MilestonesTestCaseMixin):
 @attr(shard=1)
 # setting TIME_ZONE_DISPLAYED_FOR_DEADLINES explicitly
 @override_settings(TIME_ZONE_DISPLAYED_FOR_DEADLINES="UTC")
-class BaseDueDateTests(ModuleStoreTestCase, MilestonesTestCaseMixin):
+class BaseDueDateTests(ModuleStoreTestCase):
     """
     Base class that verifies that due dates are rendered correctly on a page
     """
@@ -1829,7 +1829,7 @@ class ViewCheckerBlock(XBlock):
 
 @attr(shard=1)
 @ddt.ddt
-class TestIndexView(ModuleStoreTestCase, MilestonesTestCaseMixin):
+class TestIndexView(ModuleStoreTestCase):
     """
     Tests of the courseware.views.index view.
     """
@@ -1901,7 +1901,7 @@ class TestIndexView(ModuleStoreTestCase, MilestonesTestCaseMixin):
 
 
 @ddt.ddt
-class TestIndexViewWithVerticalPositions(ModuleStoreTestCase, MilestonesTestCaseMixin):
+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.
diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py
index c53c70faafa..8fcb0f89fd6 100644
--- a/lms/djangoapps/courseware/views/index.py
+++ b/lms/djangoapps/courseware/views/index.py
@@ -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.
diff --git a/lms/djangoapps/gating/tests/test_api.py b/lms/djangoapps/gating/tests/test_api.py
index 315bc1f0bd3..65d677a740e 100644
--- a/lms/djangoapps/gating/tests/test_api.py
+++ b/lms/djangoapps/gating/tests/test_api.py
@@ -26,10 +26,6 @@ class GatingTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
         """
         super(GatingTestCase, self).setUp()
 
-        # Patch Milestones feature flag
-        self.settings_patcher = patch.dict('django.conf.settings.FEATURES', {'MILESTONES_APP': True})
-        self.settings_patcher.start()
-
         # create course
         self.course = CourseFactory.create(
             org='edX',
@@ -81,13 +77,6 @@ class GatingTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
             display_name='untitled problem 2'
         )
 
-    def tearDown(self):
-        """
-        Tear down initial setup
-        """
-        self.settings_patcher.stop()
-        super(GatingTestCase, self).tearDown()
-
 
 class TestGetXBlockParent(GatingTestCase):
     """
diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py
index 79bbfe7ba5f..312a40adab7 100644
--- a/lms/djangoapps/instructor/tests/test_api.py
+++ b/lms/djangoapps/instructor/tests/test_api.py
@@ -39,7 +39,6 @@ from courseware.tests.factories import (
 from courseware.tests.helpers import LoginEnrollmentTestCase
 from django_comment_common.models import FORUM_ROLE_COMMUNITY_TA
 from django_comment_common.utils import seed_permissions_roles
-from milestones.tests.utils import MilestonesTestCaseMixin
 from shoppingcart.models import (
     RegistrationCodeRedemption, Order, CouponRedemption,
     PaidCourseRegistration, Coupon, Invoice, CourseRegistrationCode, CourseRegistrationCodeInvoiceItem,
@@ -3277,11 +3276,7 @@ class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTes
 @attr(shard=1)
 @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True})
 @ddt.ddt
-class TestEntranceExamInstructorAPIRegradeTask(
-        SharedModuleStoreTestCase,
-        LoginEnrollmentTestCase,
-        MilestonesTestCaseMixin
-):
+class TestEntranceExamInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
     """
     Test endpoints whereby instructors can rescore student grades,
     reset student attempts and delete state for entrance exam.
diff --git a/lms/djangoapps/mobile_api/tests/test_milestones.py b/lms/djangoapps/mobile_api/tests/test_milestones.py
index ef587922c2b..bd04664d3b4 100644
--- a/lms/djangoapps/mobile_api/tests/test_milestones.py
+++ b/lms/djangoapps/mobile_api/tests/test_milestones.py
@@ -29,7 +29,6 @@ class MobileAPIMilestonesMixin(object):
 
     @patch.dict(settings.FEATURES, {
         'ENABLE_PREREQUISITE_COURSES': True,
-        'MILESTONES_APP': True,
         'ENABLE_MKTG_SITE': True,
     })
     def test_unfulfilled_prerequisite_course(self):
@@ -38,11 +37,7 @@ class MobileAPIMilestonesMixin(object):
         self.init_course_access()
         self._verify_unfulfilled_milestone_response()
 
-    @patch.dict(settings.FEATURES, {
-        'ENABLE_PREREQUISITE_COURSES': True,
-        'MILESTONES_APP': True,
-        'ENABLE_MKTG_SITE': True,
-    })
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'ENABLE_MKTG_SITE': True})
     def test_unfulfilled_prerequisite_course_for_staff(self):
         self._add_prerequisite_course()
         self.user.is_staff = True
@@ -50,11 +45,7 @@ class MobileAPIMilestonesMixin(object):
         self.init_course_access()
         self.api_response()
 
-    @patch.dict(settings.FEATURES, {
-        'ENABLE_PREREQUISITE_COURSES': True,
-        'MILESTONES_APP': True,
-        'ENABLE_MKTG_SITE': True,
-    })
+    @patch.dict(settings.FEATURES, {'ENABLE_PREREQUISITE_COURSES': True, 'ENABLE_MKTG_SITE': True})
     def test_fulfilled_prerequisite_course(self):
         """
         Tests the case when a user fulfills existing pre-requisite course
@@ -65,11 +56,7 @@ class MobileAPIMilestonesMixin(object):
         self.init_course_access()
         self.api_response()
 
-    @patch.dict(settings.FEATURES, {
-        'ENTRANCE_EXAMS': True,
-        'MILESTONES_APP': True,
-        'ENABLE_MKTG_SITE': True,
-    })
+    @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True})
     def test_unpassed_entrance_exam(self):
         """
         Tests the case where the user has not passed the entrance exam
@@ -78,11 +65,7 @@ class MobileAPIMilestonesMixin(object):
         self.init_course_access()
         self._verify_unfulfilled_milestone_response()
 
-    @patch.dict(settings.FEATURES, {
-        'ENTRANCE_EXAMS': True,
-        'MILESTONES_APP': True,
-        'ENABLE_MKTG_SITE': True,
-    })
+    @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True})
     def test_unpassed_entrance_exam_for_staff(self):
         self._add_entrance_exam()
         self.user.is_staff = True
@@ -90,11 +73,7 @@ class MobileAPIMilestonesMixin(object):
         self.init_course_access()
         self.api_response()
 
-    @patch.dict(settings.FEATURES, {
-        'ENTRANCE_EXAMS': True,
-        'MILESTONES_APP': True,
-        'ENABLE_MKTG_SITE': True,
-    })
+    @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True, 'ENABLE_MKTG_SITE': True})
     def test_passed_entrance_exam(self):
         """
         Tests access when user has passed the entrance exam
diff --git a/lms/djangoapps/mobile_api/users/tests.py b/lms/djangoapps/mobile_api/users/tests.py
index 6e86e72adf0..8bd837f60c4 100644
--- a/lms/djangoapps/mobile_api/users/tests.py
+++ b/lms/djangoapps/mobile_api/users/tests.py
@@ -138,7 +138,6 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
 
     @patch.dict(settings.FEATURES, {
         'ENABLE_PREREQUISITE_COURSES': True,
-        'MILESTONES_APP': True,
         'DISABLE_START_DATES': False,
         'ENABLE_MKTG_SITE': True,
     })
diff --git a/lms/djangoapps/mobile_api/video_outlines/tests.py b/lms/djangoapps/mobile_api/video_outlines/tests.py
index b13e173766e..877bb87b7cc 100644
--- a/lms/djangoapps/mobile_api/video_outlines/tests.py
+++ b/lms/djangoapps/mobile_api/video_outlines/tests.py
@@ -10,7 +10,6 @@ from collections import namedtuple
 import ddt
 from nose.plugins.attrib import attr
 from edxval import api
-from milestones.tests.utils import MilestonesTestCaseMixin
 from xmodule.modulestore.tests.factories import ItemFactory
 from xmodule.video_module import transcripts_utils
 from xmodule.modulestore.django import modulestore
diff --git a/openedx/core/lib/gating/tests/test_api.py b/openedx/core/lib/gating/tests/test_api.py
index 6764abe78a3..0fa138a0a91 100644
--- a/openedx/core/lib/gating/tests/test_api.py
+++ b/openedx/core/lib/gating/tests/test_api.py
@@ -16,7 +16,6 @@ from student.tests.factories import UserFactory
 
 @attr(shard=2)
 @ddt
-@patch.dict('django.conf.settings.FEATURES', {'MILESTONES_APP': True})
 class TestGatingApi(ModuleStoreTestCase, MilestonesTestCaseMixin):
     """
     Tests for the gating API
diff --git a/openedx/tests/xblock_integration/test_done.py b/openedx/tests/xblock_integration/test_done.py
index a8e8c435cd8..057165acd06 100644
--- a/openedx/tests/xblock_integration/test_done.py
+++ b/openedx/tests/xblock_integration/test_done.py
@@ -4,14 +4,10 @@ Tests for the DoneXBlock.
 This is nice as a simple example of the edX XBlock test framework.
 '''
 
-from mock import patch
 from openedx.tests.xblock_integration.xblock_testcase import XBlockTestCase
 
 
-# We set MILESTONES_APP to False to avoid XBlock access issues in this test,
-# which is meant to exist independent of our particular LMS instance.
 # pylint: disable=abstract-method
-@patch.dict('django.conf.settings.FEATURES', {'MILESTONES_APP': False})
 class TestDone(XBlockTestCase):
     """
     Simple tests for the completion XBlock. We set up a page with two
diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt
index 13527b74c8b..50050df456a 100644
--- a/requirements/edx/github.txt
+++ b/requirements/edx/github.txt
@@ -84,7 +84,7 @@ git+https://github.com/pmitros/RecommenderXBlock.git@v1.1#egg=recommender-xblock
 git+https://github.com/solashirai/crowdsourcehinter.git@518605f0a95190949fe77bd39158450639e2e1dc#egg=crowdsourcehinter-xblock==0.1
 -e git+https://github.com/pmitros/RateXBlock.git@367e19c0f6eac8a5f002fd0f1559555f8e74bfff#egg=rate-xblock
 -e git+https://github.com/pmitros/DoneXBlock.git@857bf365f19c904d7e48364428f6b93ff153fabd#egg=done-xblock
-git+https://github.com/edx/edx-milestones.git@v0.1.9#egg=edx-milestones==0.1.9
+git+https://github.com/edx/edx-milestones.git@v0.1.10#egg=edx-milestones==0.1.10
 git+https://github.com/edx/xblock-utils.git@v1.0.2#egg=xblock-utils==1.0.2
 -e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive
 -e git+https://github.com/edx/edx-reverification-block.git@0.0.5#egg=edx-reverification-block==0.0.5
-- 
GitLab