{"action":"created","comment":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/comments/22847033","id":22847033,"diff_hunk":"@@ -0,0 +1,151 @@\n+\"\"\"\n+Helper methods for milestones api calls.\n+\"\"\"\n+\n+from django.utils.translation import ugettext as _\n+from opaque_keys import InvalidKeyError\n+from opaque_keys.edx.locations import SlashSeparatedCourseKey\n+from opaque_keys.edx.keys import CourseKey\n+from xmodule.modulestore.django import modulestore\n+from milestones.api import (\n+    get_course_milestones,\n+    add_milestone,\n+    add_course_milestone,\n+    remove_course_milestone,\n+    get_course_milestones_fulfillment_paths,\n+    add_user_milestone,\n+    get_user_milestones,\n+)\n+from django.conf import settings\n+\n+\n+def add_prerequisite_course(course_key, prerequisite_course_key):\n+    \"\"\"\n+    It would create a milestone for given course and set it as\n+    requirement milestone for given course and set it a fulfilment\n+    milestone for pre-requisite course.\n+    \"\"\"\n+    # create a milestone\n+    milestone = add_milestone({\n+        'name': _('Course {} requires {}'.format(unicode(course_key), unicode(prerequisite_course_key))),\n+        'namespace': unicode(prerequisite_course_key),\n+        'description': _('System defined milestone'),\n+    })\n+    # add requirement course milestone\n+    add_course_milestone(course_key, 'requires', milestone)\n+\n+    # add fulfillment course milestone\n+    add_course_milestone(prerequisite_course_key, 'fulfills', milestone)\n+\n+\n+def remove_prerequisite_course(course_key, milestone):\n+    \"\"\"\n+    It would remove pre-requisite course milestone for a course\n+    \"\"\"\n+\n+    remove_course_milestone(\n+        course_key,\n+        milestone,\n+    )\n+\n+\n+def set_prerequisite_courses(course_key, prerequisite_course_keys):\n+    \"\"\"\n+    It would remove any existing requirement milestones for the given `course_key`\n+    and create new milestones for each pre requisite course in `prerequisite_course_keys`.\n+    To only remove course milestones pass `course_key` and empty list or\n+    None as `prerequisite_course_keys` .\n+    \"\"\"\n+    #remove any existing requirement milestones with this pre-requisite course as requirement\n+    course_milestones = get_course_milestones(course_key=course_key, relationship=\"requires\")\n+    if course_milestones:\n+        for milestone in course_milestones:\n+            remove_prerequisite_course(course_key, milestone)\n+\n+    # add milestones if pre-requisite course is selected\n+    if prerequisite_course_keys:\n+        for prerequisite_course_key_string in prerequisite_course_keys:\n+            prerequisite_course_key = CourseKey.from_string(prerequisite_course_key_string)\n+            add_prerequisite_course(course_key, prerequisite_course_key)\n+\n+\n+def get_pre_requisite_courses_not_completed(user, enrolled_courses):  # pylint: disable=invalid-name\n+    \"\"\"\n+    It would make dict of prerequisite courses not completed by user among courses\n+    user has enrolled in. It calls the fulfilment api of milestones app and\n+    iterates over all fulfillments of user not achieved to make dict of\n+    prerequisites yet to be completed.\n+    \"\"\"\n+    pre_requisite_courses = {}\n+    if settings.FEATURES.get('ENABLE_PREREQUISITE_COURSES'):\n+        for course, __ in enrolled_courses:\n+            required_courses = []\n+            # if course has pre-requisites then fetch fulfilment path\n+            if course.pre_requisite_courses:\n+                fulfilment_paths = get_course_milestones_fulfillment_paths(course.id, {'id': user.id})\n+                for milestone_key, milestone_value in fulfilment_paths.items():  # pylint: disable=unused-variable\n+                    for key, value in milestone_value.items():\n+                        if key == 'courses' and value:\n+                            for required_course in value:\n+                                required_course_key = CourseKey.from_string(required_course['course_id'])\n+                                required_course_descriptor = modulestore().get_course(required_course_key)\n+                                required_courses.append({\n+                                    'key': required_course_key,\n+                                    'display': ' '.join([\n+                                        required_course_descriptor.display_org_with_default,\n+                                        required_course_descriptor.display_number_with_default\n+                                    ])\n+                                })\n+\n+                # if there are required courses add to dict\n+            if required_courses:\n+                pre_requisite_courses[course.id] = {'courses': required_courses}\n+    return pre_requisite_courses\n+\n+\n+def get_prerequisite_courses_display(course_descriptor):  # pylint: disable=invalid-name\n+    \"\"\"\n+    It would retrieve pre-requisite courses, make display strings\n+    and return them as list\n+    \"\"\"\n+    pre_requisite_courses = []\n+    if settings.FEATURES.get('ENABLE_PREREQUISITE_COURSES', False) and course_descriptor.pre_requisite_courses:\n+        for course_id in course_descriptor.pre_requisite_courses:\n+            course_key = CourseKey.from_string(course_id)\n+            required_course_descriptor = modulestore().get_course(course_key)","path":"common/djangoapps/util/milestones_helpers.py","position":112,"original_position":115,"commit_id":"103da52ae11132e4d3f29cdf9d59bf1d578d1301","original_commit_id":"18935e487854131189fdb97f6325a95c990580ec","user":{"login":"ziafazal","id":434995,"avatar_url":"https://avatars.githubusercontent.com/u/434995?v=3","gravatar_id":"","url":"https://api.github.com/users/ziafazal","html_url":"https://github.com/ziafazal","followers_url":"https://api.github.com/users/ziafazal/followers","following_url":"https://api.github.com/users/ziafazal/following{/other_user}","gists_url":"https://api.github.com/users/ziafazal/gists{/gist_id}","starred_url":"https://api.github.com/users/ziafazal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ziafazal/subscriptions","organizations_url":"https://api.github.com/users/ziafazal/orgs","repos_url":"https://api.github.com/users/ziafazal/repos","events_url":"https://api.github.com/users/ziafazal/events{/privacy}","received_events_url":"https://api.github.com/users/ziafazal/received_events","type":"User","site_admin":false},"body":"Created helper method.","created_at":"2015-01-13T07:49:30Z","updated_at":"2015-01-13T07:49:30Z","html_url":"https://github.com/edx/edx-platform/pull/6126#discussion_r22847033","pull_request_url":"https://api.github.com/repos/edx/edx-platform/pulls/6126","_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments/22847033"},"html":{"href":"https://github.com/edx/edx-platform/pull/6126#discussion_r22847033"},"pull_request":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/6126"}}},"pull_request":{"url":"https://api.github.com/repos/edx/edx-platform/pulls/6126","id":25423711,"html_url":"https://github.com/edx/edx-platform/pull/6126","diff_url":"https://github.com/edx/edx-platform/pull/6126.diff","patch_url":"https://github.com/edx/edx-platform/pull/6126.patch","issue_url":"https://api.github.com/repos/edx/edx-platform/issues/6126","number":6126,"state":"open","locked":false,"title":"Ziafazal/add pre requisite course via milestones app","user":{"login":"ziafazal","id":434995,"avatar_url":"https://avatars.githubusercontent.com/u/434995?v=3","gravatar_id":"","url":"https://api.github.com/users/ziafazal","html_url":"https://github.com/ziafazal","followers_url":"https://api.github.com/users/ziafazal/followers","following_url":"https://api.github.com/users/ziafazal/following{/other_user}","gists_url":"https://api.github.com/users/ziafazal/gists{/gist_id}","starred_url":"https://api.github.com/users/ziafazal/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ziafazal/subscriptions","organizations_url":"https://api.github.com/users/ziafazal/orgs","repos_url":"https://api.github.com/users/ziafazal/repos","events_url":"https://api.github.com/users/ziafazal/events{/privacy}","received_events_url":"https://api.github.com/users/ziafazal/received_events","type":"User","site_admin":false},"body":"@mattdrayer added pre-requisite feature via milestones app. It would show a drop down for course authors to select from list available courses as a pre-requisite course in \"Settings & Details\" page. Inside lms it would show the appropriate messaging under side bar of course about page.","created_at":"2014-12-03T14:50:39Z","updated_at":"2015-01-13T07:49:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3a7dfdb72df776d1c57f67839188cafc336bb96d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/edx/edx-platform/pulls/6126/commits","review_comments_url":"https://api.github.com/repos/edx/edx-platform/pulls/6126/comments","review_comment_url":"https://api.github.com/repos/edx/edx-platform/pulls/comments/{number}","comments_url":"https://api.github.com/repos/edx/edx-platform/issues/6126/comments","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/103da52ae11132e4d3f29cdf9d59bf1d578d1301","head":{"label":"edx:ziafazal/add-pre-requisite-course-via-milestones-app","ref":"ziafazal/add-pre-requisite-course-via-milestones-app","sha":"103da52ae11132e4d3f29cdf9d59bf1d578d1301","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"Open edX, the edX platform that powers http://edx.org","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments/{number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-01-13T07:11:38Z","pushed_at":"2015-01-13T07:45:23Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://openedx.org/","size":1575427,"stargazers_count":1666,"watchers_count":1666,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":954,"mirror_url":null,"open_issues_count":146,"forks":954,"open_issues":146,"watchers":1666,"default_branch":"master"}},"base":{"label":"edx:master","ref":"master","sha":"30b572b1b19c0525f2fba98bf5491583fbd0d1df","user":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"repo":{"id":10391073,"name":"edx-platform","full_name":"edx/edx-platform","owner":{"login":"edx","id":3179841,"avatar_url":"https://avatars.githubusercontent.com/u/3179841?v=3","gravatar_id":"","url":"https://api.github.com/users/edx","html_url":"https://github.com/edx","followers_url":"https://api.github.com/users/edx/followers","following_url":"https://api.github.com/users/edx/following{/other_user}","gists_url":"https://api.github.com/users/edx/gists{/gist_id}","starred_url":"https://api.github.com/users/edx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/edx/subscriptions","organizations_url":"https://api.github.com/users/edx/orgs","repos_url":"https://api.github.com/users/edx/repos","events_url":"https://api.github.com/users/edx/events{/privacy}","received_events_url":"https://api.github.com/users/edx/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/edx/edx-platform","description":"Open edX, the edX platform that powers http://edx.org","fork":false,"url":"https://api.github.com/repos/edx/edx-platform","forks_url":"https://api.github.com/repos/edx/edx-platform/forks","keys_url":"https://api.github.com/repos/edx/edx-platform/keys{/key_id}","collaborators_url":"https://api.github.com/repos/edx/edx-platform/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/edx/edx-platform/teams","hooks_url":"https://api.github.com/repos/edx/edx-platform/hooks","issue_events_url":"https://api.github.com/repos/edx/edx-platform/issues/events{/number}","events_url":"https://api.github.com/repos/edx/edx-platform/events","assignees_url":"https://api.github.com/repos/edx/edx-platform/assignees{/user}","branches_url":"https://api.github.com/repos/edx/edx-platform/branches{/branch}","tags_url":"https://api.github.com/repos/edx/edx-platform/tags","blobs_url":"https://api.github.com/repos/edx/edx-platform/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/edx/edx-platform/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/edx/edx-platform/git/refs{/sha}","trees_url":"https://api.github.com/repos/edx/edx-platform/git/trees{/sha}","statuses_url":"https://api.github.com/repos/edx/edx-platform/statuses/{sha}","languages_url":"https://api.github.com/repos/edx/edx-platform/languages","stargazers_url":"https://api.github.com/repos/edx/edx-platform/stargazers","contributors_url":"https://api.github.com/repos/edx/edx-platform/contributors","subscribers_url":"https://api.github.com/repos/edx/edx-platform/subscribers","subscription_url":"https://api.github.com/repos/edx/edx-platform/subscription","commits_url":"https://api.github.com/repos/edx/edx-platform/commits{/sha}","git_commits_url":"https://api.github.com/repos/edx/edx-platform/git/commits{/sha}","comments_url":"https://api.github.com/repos/edx/edx-platform/comments{/number}","issue_comment_url":"https://api.github.com/repos/edx/edx-platform/issues/comments/{number}","contents_url":"https://api.github.com/repos/edx/edx-platform/contents/{+path}","compare_url":"https://api.github.com/repos/edx/edx-platform/compare/{base}...{head}","merges_url":"https://api.github.com/repos/edx/edx-platform/merges","archive_url":"https://api.github.com/repos/edx/edx-platform/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/edx/edx-platform/downloads","issues_url":"https://api.github.com/repos/edx/edx-platform/issues{/number}","pulls_url":"https://api.github.com/repos/edx/edx-platform/pulls{/number}","milestones_url":"https://api.github.com/repos/edx/edx-platform/milestones{/number}","notifications_url":"https://api.github.com/repos/edx/edx-platform/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/edx/edx-platform/labels{/name}","releases_url":"https://api.github.com/repos/edx/edx-platform/releases{/id}","created_at":"2013-05-30T20:20:38Z","updated_at":"2015-01-13T07:11:38Z","pushed_at":"2015-01-13T07:45:23Z","git_url":"git://github.com/edx/edx-platform.git","ssh_url":"git@github.com:edx/edx-platform.git","clone_url":"https://github.com/edx/edx-platform.git","svn_url":"https://github.com/edx/edx-platform","homepage":"http://openedx.org/","size":1575427,"stargazers_count":1666,"watchers_count":1666,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":954,"mirror_url":null,"open_issues_count":146,"forks":954,"open_issues":146,"watchers":1666,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/6126"},"html":{"href":"https://github.com/edx/edx-platform/pull/6126"},"issue":{"href":"https://api.github.com/repos/edx/edx-platform/issues/6126"},"comments":{"href":"https://api.github.com/repos/edx/edx-platform/issues/6126/comments"},"review_comments":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/6126/comments"},"review_comment":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/edx/edx-platform/pulls/6126/commits"},"statuses":{"href":"https://api.github.com/repos/edx/edx-platform/statuses/103da52ae11132e4d3f29cdf9d59bf1d578d1301"}}}}