{"action":"created","comment":{"url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/comments/228240306","pull_request_review_id":168467994,"id":228240306,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyODI0MDMwNg==","diff_hunk":"@@ -1,27 +1,130 @@\n \"\"\" Middleware for seb_openedx \"\"\"\n \n import sys\n+import inspect\n+from django.http import HttpResponseNotFound\n from django.utils.deprecation import MiddlewareMixin\n+from django.utils.six.moves import filter as sixfilter  # pylint: disable=import-error\n from django.conf import settings\n from opaque_keys.edx.keys import CourseKey\n-from seb_openedx.edxapp_wrapper.edxmako_module import render_to_response\n+from web_fragments.fragment import Fragment\n+from seb_openedx.edxapp_wrapper.edxmako_module import render_to_response, render_to_string\n+from seb_openedx.edxapp_wrapper.get_courseware_module import get_courseware_module\n from seb_openedx.permissions import get_enabled_permission_classes\n+from seb_openedx.seb_courseware_index import SebCoursewareIndex\n+from seb_openedx.edxapp_wrapper.get_chapter_from_location import get_chapter_from_location\n+\n+SEB_WHITELIST_PATHS = getattr(settings, 'SEB_WHITELIST_PATHS', [])\n+SEB_BLACKLIST_CHAPTERS = getattr(settings, 'SEB_BLACKLIST_CHAPTERS', [])\n \n \n class SecureExamBrowserMiddleware(MiddlewareMixin):\n     \"\"\" Middleware for seb_openedx \"\"\"\n \n-    # pylint: disable=inconsistent-return-statements\n     def process_view(self, request, view_func, view_args, view_kwargs):\n         \"\"\" Start point of to d4etermine cms or lms \"\"\"\n+        courseware = get_courseware_module()\n         course_key_string = view_kwargs.get('course_key_string') or view_kwargs.get('course_id')\n         course_key = CourseKey.from_string(course_key_string) if course_key_string else None\n+        access_denied = False\n+\n         if course_key:\n+            # By default is all denied\n+            access_denied = True\n+\n+            if self.is_whitelisted_view(request, course_key):\n+                # First: Broad white-listing\n+                access_denied = False\n+\n+            if self.is_blacklisted_chapter(request, course_key):\n+                # Second: Granular white-listing\n+                access_denied = True\n+\n             active_comps = get_enabled_permission_classes()\n             for permission in active_comps:\n                 if permission().check(request, course_key):\n-                    return\n-            return render_to_response('seb-403.html', status=403)\n+                    access_denied = False\n+\n+        if access_denied:\n+            is_courseware_view = bool(view_func.__name__ == courseware.views.index.CoursewareIndex.__name__)\n+            if is_courseware_view:\n+                return self.courseware_error_response(request, *view_args, **view_kwargs)\n+            return self.generic_error_response(request, course_key)\n+        return None\n+\n+    def is_whitelisted_view(self, request, course_key):\n+        \"\"\" First broad filter: whitelisting of paths/tabs \"\"\"\n+\n+        # Whitelisting logic by alias\n+        aliases = {\n+            'discussion.views': 'discussion',\n+            'course_wiki.views': 'wiki',\n+            'openedx.features.course_experience': 'course-outline',\n+        }\n+\n+        views_module = inspect.getmodule(request.resolver_match.func).__name__\n+\n+        alias_current_path = next(sixfilter(lambda k: aliases[k] if views_module.startswith(k) else None, aliases), None)\n+\n+        if alias_current_path in SEB_WHITELIST_PATHS:\n+            return True\n+\n+        # Whitelisting xblocks when courseware\n+        if 'courseware' in SEB_WHITELIST_PATHS and self.is_xblock_request(request):\n+            return True\n+\n+        # Whitelisting by url name\n+        if request.resolver_match.url_name:\n+            url_names_allowed = list(SEB_WHITELIST_PATHS) + ['jump_to', 'jump_to_id']\n+            for url_name in url_names_allowed:\n+                if request.resolver_match.url_name.startswith(url_name):\n+                    return True\n+\n+        return False\n+\n+    def is_blacklisted_chapter(self, request, course_key):\n+        \"\"\" Second more granular filter: blacklisting of specific chapters \"\"\"\n+        chapter = request.resolver_match.kwargs.get('chapter')\n+\n+        if not SEB_BLACKLIST_CHAPTERS:\n+            return False\n+\n+        if chapter in SEB_BLACKLIST_CHAPTERS:\n+            return True\n+\n+        if 'courseware' in SEB_WHITELIST_PATHS and self.is_xblock_request(request):\n+            usage_id = request.resolver_match.kwargs.get('usage_id')\n+            if usage_id:\n+                chapter = get_chapter_from_location(usage_id, course_key)\n+                if chapter in SEB_BLACKLIST_CHAPTERS:\n+                    return True\n+        return False\n+\n+    def courseware_error_response(self, request, *view_args, **view_kwargs):\n+        \"\"\" error response when a chapter is being blocked \"\"\"\n+        html = Fragment()\n+        html.add_content(render_to_string('seb-403-error-message.html', {}))\n+        SebCoursewareIndex.set_context_fragment(html)\n+        return SebCoursewareIndex.as_view()(request, *view_args, **view_kwargs)\n+\n+    def generic_error_response(self, request, course_key):\n+        \"\"\" generic error response, full page 403 error (with course menu) \"\"\"\n+        courseware = get_courseware_module()\n+        try:\n+            course = courseware.courses.get_course(course_key, depth=2)","path":"seb_openedx/middleware.py","position":118,"original_position":118,"commit_id":"57e4fc697a5e911b264b5ffd19bf50b0ff36b713","original_commit_id":"57e4fc697a5e911b264b5ffd19bf50b0ff36b713","user":{"login":"Ivanca","id":907138,"node_id":"MDQ6VXNlcjkwNzEzOA==","avatar_url":"https://avatars3.githubusercontent.com/u/907138?v=4","gravatar_id":"","url":"https://api.github.com/users/Ivanca","html_url":"https://github.com/Ivanca","followers_url":"https://api.github.com/users/Ivanca/followers","following_url":"https://api.github.com/users/Ivanca/following{/other_user}","gists_url":"https://api.github.com/users/Ivanca/gists{/gist_id}","starred_url":"https://api.github.com/users/Ivanca/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ivanca/subscriptions","organizations_url":"https://api.github.com/users/Ivanca/orgs","repos_url":"https://api.github.com/users/Ivanca/repos","events_url":"https://api.github.com/users/Ivanca/events{/privacy}","received_events_url":"https://api.github.com/users/Ivanca/received_events","type":"User","site_admin":false},"body":"We use get_courseware_module on another file as well: seb_courseware_index.py\r\nAnd we probably gonna be using some attributes (and deeper ones) of the courseware_module in the near future, so having separate backends for each function will result in too many files.","created_at":"2018-10-25T16:13:32Z","updated_at":"2018-10-25T16:13:32Z","html_url":"https://github.com/eduNEXT/seb-openedx/pull/12#discussion_r228240306","pull_request_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/comments/228240306"},"html":{"href":"https://github.com/eduNEXT/seb-openedx/pull/12#discussion_r228240306"},"pull_request":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12"}},"in_reply_to_id":228237411},"pull_request":{"url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12","id":223694706,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIzNjk0NzA2","html_url":"https://github.com/eduNEXT/seb-openedx/pull/12","diff_url":"https://github.com/eduNEXT/seb-openedx/pull/12.diff","patch_url":"https://github.com/eduNEXT/seb-openedx/pull/12.patch","issue_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/12","number":12,"state":"open","locked":false,"title":"Making SEB-configuration more granular","user":{"login":"Ivanca","id":907138,"node_id":"MDQ6VXNlcjkwNzEzOA==","avatar_url":"https://avatars3.githubusercontent.com/u/907138?v=4","gravatar_id":"","url":"https://api.github.com/users/Ivanca","html_url":"https://github.com/Ivanca","followers_url":"https://api.github.com/users/Ivanca/followers","following_url":"https://api.github.com/users/Ivanca/following{/other_user}","gists_url":"https://api.github.com/users/Ivanca/gists{/gist_id}","starred_url":"https://api.github.com/users/Ivanca/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ivanca/subscriptions","organizations_url":"https://api.github.com/users/Ivanca/orgs","repos_url":"https://api.github.com/users/Ivanca/repos","events_url":"https://api.github.com/users/Ivanca/events{/privacy}","received_events_url":"https://api.github.com/users/Ivanca/received_events","type":"User","site_admin":false},"body":"There is 2 new configuration options:\r\nSEB_WHITELIST_PATHS = []\r\nSEB_BLACKLIST_CHAPTERS = []\r\n\r\n**SEB_WHITELIST_PATHS** is a list of paths that can be accessed, it may contain one of the following values: 'wiki', 'course-outline', 'courseware', 'progress', 'discussion'; plus any other url name (e.g. useful for custom tabs)\r\n\r\n**SEB_BLACKLIST_CHAPTERS** is a list of chapters that are blocked even when 'courseware' has been white-listed; e.g. useful to block the \"exam\" chapter but not the rest.\r\n\r\nRight now those 2 configurations are global and not in a course-basis; may be better to agree on the current state before making it so.","created_at":"2018-10-17T17:41:50Z","updated_at":"2018-10-25T16:13:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"735e5595745388252c1007b20a8e8b5a9dbcc7c7","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12/commits","review_comments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12/comments","review_comment_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/comments{/number}","comments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/12/comments","statuses_url":"https://api.github.com/repos/eduNEXT/seb-openedx/statuses/57e4fc697a5e911b264b5ffd19bf50b0ff36b713","head":{"label":"eduNEXT:icc/make-seb-configuration-more-granuarly","ref":"icc/make-seb-configuration-more-granuarly","sha":"57e4fc697a5e911b264b5ffd19bf50b0ff36b713","user":{"login":"eduNEXT","id":5911140,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU5MTExNDA=","avatar_url":"https://avatars0.githubusercontent.com/u/5911140?v=4","gravatar_id":"","url":"https://api.github.com/users/eduNEXT","html_url":"https://github.com/eduNEXT","followers_url":"https://api.github.com/users/eduNEXT/followers","following_url":"https://api.github.com/users/eduNEXT/following{/other_user}","gists_url":"https://api.github.com/users/eduNEXT/gists{/gist_id}","starred_url":"https://api.github.com/users/eduNEXT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eduNEXT/subscriptions","organizations_url":"https://api.github.com/users/eduNEXT/orgs","repos_url":"https://api.github.com/users/eduNEXT/repos","events_url":"https://api.github.com/users/eduNEXT/events{/privacy}","received_events_url":"https://api.github.com/users/eduNEXT/received_events","type":"Organization","site_admin":false},"repo":{"id":146632279,"node_id":"MDEwOlJlcG9zaXRvcnkxNDY2MzIyNzk=","name":"seb-openedx","full_name":"eduNEXT/seb-openedx","private":false,"owner":{"login":"eduNEXT","id":5911140,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU5MTExNDA=","avatar_url":"https://avatars0.githubusercontent.com/u/5911140?v=4","gravatar_id":"","url":"https://api.github.com/users/eduNEXT","html_url":"https://github.com/eduNEXT","followers_url":"https://api.github.com/users/eduNEXT/followers","following_url":"https://api.github.com/users/eduNEXT/following{/other_user}","gists_url":"https://api.github.com/users/eduNEXT/gists{/gist_id}","starred_url":"https://api.github.com/users/eduNEXT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eduNEXT/subscriptions","organizations_url":"https://api.github.com/users/eduNEXT/orgs","repos_url":"https://api.github.com/users/eduNEXT/repos","events_url":"https://api.github.com/users/eduNEXT/events{/privacy}","received_events_url":"https://api.github.com/users/eduNEXT/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/eduNEXT/seb-openedx","description":null,"fork":false,"url":"https://api.github.com/repos/eduNEXT/seb-openedx","forks_url":"https://api.github.com/repos/eduNEXT/seb-openedx/forks","keys_url":"https://api.github.com/repos/eduNEXT/seb-openedx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/eduNEXT/seb-openedx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/eduNEXT/seb-openedx/teams","hooks_url":"https://api.github.com/repos/eduNEXT/seb-openedx/hooks","issue_events_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/events{/number}","events_url":"https://api.github.com/repos/eduNEXT/seb-openedx/events","assignees_url":"https://api.github.com/repos/eduNEXT/seb-openedx/assignees{/user}","branches_url":"https://api.github.com/repos/eduNEXT/seb-openedx/branches{/branch}","tags_url":"https://api.github.com/repos/eduNEXT/seb-openedx/tags","blobs_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/refs{/sha}","trees_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/eduNEXT/seb-openedx/statuses/{sha}","languages_url":"https://api.github.com/repos/eduNEXT/seb-openedx/languages","stargazers_url":"https://api.github.com/repos/eduNEXT/seb-openedx/stargazers","contributors_url":"https://api.github.com/repos/eduNEXT/seb-openedx/contributors","subscribers_url":"https://api.github.com/repos/eduNEXT/seb-openedx/subscribers","subscription_url":"https://api.github.com/repos/eduNEXT/seb-openedx/subscription","commits_url":"https://api.github.com/repos/eduNEXT/seb-openedx/commits{/sha}","git_commits_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/commits{/sha}","comments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/comments{/number}","issue_comment_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/comments{/number}","contents_url":"https://api.github.com/repos/eduNEXT/seb-openedx/contents/{+path}","compare_url":"https://api.github.com/repos/eduNEXT/seb-openedx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/eduNEXT/seb-openedx/merges","archive_url":"https://api.github.com/repos/eduNEXT/seb-openedx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/eduNEXT/seb-openedx/downloads","issues_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues{/number}","pulls_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls{/number}","milestones_url":"https://api.github.com/repos/eduNEXT/seb-openedx/milestones{/number}","notifications_url":"https://api.github.com/repos/eduNEXT/seb-openedx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/eduNEXT/seb-openedx/labels{/name}","releases_url":"https://api.github.com/repos/eduNEXT/seb-openedx/releases{/id}","deployments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/deployments","created_at":"2018-08-29T17:04:18Z","updated_at":"2018-10-17T17:55:10Z","pushed_at":"2018-10-25T16:04:06Z","git_url":"git://github.com/eduNEXT/seb-openedx.git","ssh_url":"git@github.com:eduNEXT/seb-openedx.git","clone_url":"https://github.com/eduNEXT/seb-openedx.git","svn_url":"https://github.com/eduNEXT/seb-openedx","homepage":null,"size":90,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":3,"license":null,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"base":{"label":"eduNEXT:master","ref":"master","sha":"2946552fe6c15c6b04ad72dcc2b45d1453a63527","user":{"login":"eduNEXT","id":5911140,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU5MTExNDA=","avatar_url":"https://avatars0.githubusercontent.com/u/5911140?v=4","gravatar_id":"","url":"https://api.github.com/users/eduNEXT","html_url":"https://github.com/eduNEXT","followers_url":"https://api.github.com/users/eduNEXT/followers","following_url":"https://api.github.com/users/eduNEXT/following{/other_user}","gists_url":"https://api.github.com/users/eduNEXT/gists{/gist_id}","starred_url":"https://api.github.com/users/eduNEXT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eduNEXT/subscriptions","organizations_url":"https://api.github.com/users/eduNEXT/orgs","repos_url":"https://api.github.com/users/eduNEXT/repos","events_url":"https://api.github.com/users/eduNEXT/events{/privacy}","received_events_url":"https://api.github.com/users/eduNEXT/received_events","type":"Organization","site_admin":false},"repo":{"id":146632279,"node_id":"MDEwOlJlcG9zaXRvcnkxNDY2MzIyNzk=","name":"seb-openedx","full_name":"eduNEXT/seb-openedx","private":false,"owner":{"login":"eduNEXT","id":5911140,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU5MTExNDA=","avatar_url":"https://avatars0.githubusercontent.com/u/5911140?v=4","gravatar_id":"","url":"https://api.github.com/users/eduNEXT","html_url":"https://github.com/eduNEXT","followers_url":"https://api.github.com/users/eduNEXT/followers","following_url":"https://api.github.com/users/eduNEXT/following{/other_user}","gists_url":"https://api.github.com/users/eduNEXT/gists{/gist_id}","starred_url":"https://api.github.com/users/eduNEXT/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/eduNEXT/subscriptions","organizations_url":"https://api.github.com/users/eduNEXT/orgs","repos_url":"https://api.github.com/users/eduNEXT/repos","events_url":"https://api.github.com/users/eduNEXT/events{/privacy}","received_events_url":"https://api.github.com/users/eduNEXT/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/eduNEXT/seb-openedx","description":null,"fork":false,"url":"https://api.github.com/repos/eduNEXT/seb-openedx","forks_url":"https://api.github.com/repos/eduNEXT/seb-openedx/forks","keys_url":"https://api.github.com/repos/eduNEXT/seb-openedx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/eduNEXT/seb-openedx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/eduNEXT/seb-openedx/teams","hooks_url":"https://api.github.com/repos/eduNEXT/seb-openedx/hooks","issue_events_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/events{/number}","events_url":"https://api.github.com/repos/eduNEXT/seb-openedx/events","assignees_url":"https://api.github.com/repos/eduNEXT/seb-openedx/assignees{/user}","branches_url":"https://api.github.com/repos/eduNEXT/seb-openedx/branches{/branch}","tags_url":"https://api.github.com/repos/eduNEXT/seb-openedx/tags","blobs_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/refs{/sha}","trees_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/eduNEXT/seb-openedx/statuses/{sha}","languages_url":"https://api.github.com/repos/eduNEXT/seb-openedx/languages","stargazers_url":"https://api.github.com/repos/eduNEXT/seb-openedx/stargazers","contributors_url":"https://api.github.com/repos/eduNEXT/seb-openedx/contributors","subscribers_url":"https://api.github.com/repos/eduNEXT/seb-openedx/subscribers","subscription_url":"https://api.github.com/repos/eduNEXT/seb-openedx/subscription","commits_url":"https://api.github.com/repos/eduNEXT/seb-openedx/commits{/sha}","git_commits_url":"https://api.github.com/repos/eduNEXT/seb-openedx/git/commits{/sha}","comments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/comments{/number}","issue_comment_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/comments{/number}","contents_url":"https://api.github.com/repos/eduNEXT/seb-openedx/contents/{+path}","compare_url":"https://api.github.com/repos/eduNEXT/seb-openedx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/eduNEXT/seb-openedx/merges","archive_url":"https://api.github.com/repos/eduNEXT/seb-openedx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/eduNEXT/seb-openedx/downloads","issues_url":"https://api.github.com/repos/eduNEXT/seb-openedx/issues{/number}","pulls_url":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls{/number}","milestones_url":"https://api.github.com/repos/eduNEXT/seb-openedx/milestones{/number}","notifications_url":"https://api.github.com/repos/eduNEXT/seb-openedx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/eduNEXT/seb-openedx/labels{/name}","releases_url":"https://api.github.com/repos/eduNEXT/seb-openedx/releases{/id}","deployments_url":"https://api.github.com/repos/eduNEXT/seb-openedx/deployments","created_at":"2018-08-29T17:04:18Z","updated_at":"2018-10-17T17:55:10Z","pushed_at":"2018-10-25T16:04:06Z","git_url":"git://github.com/eduNEXT/seb-openedx.git","ssh_url":"git@github.com:eduNEXT/seb-openedx.git","clone_url":"https://github.com/eduNEXT/seb-openedx.git","svn_url":"https://github.com/eduNEXT/seb-openedx","homepage":null,"size":90,"stargazers_count":2,"watchers_count":2,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":3,"license":null,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12"},"html":{"href":"https://github.com/eduNEXT/seb-openedx/pull/12"},"issue":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/12"},"comments":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/issues/12/comments"},"review_comments":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12/comments"},"review_comment":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/pulls/12/commits"},"statuses":{"href":"https://api.github.com/repos/eduNEXT/seb-openedx/statuses/57e4fc697a5e911b264b5ffd19bf50b0ff36b713"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"Ivanca"}}