{"action":"created","comment":{"url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/comments/52743703","id":52743703,"diff_hunk":"@@ -125,7 +126,180 @@ def real_user_id(self, anonymous_student_id):\n         return self._known_real_user_ids[anonymous_student_id]\n \n \n-class WorkgroupAwareXBlockMixin(UserAwareXBlockMixin, CourseAwareXBlockMixin):\n+class SettingsMixin(object):\n+\n+    def _get_setting(self, setting, default):\n+        result = default\n+        settings_service = self.runtime.service(self, \"settings\")\n+        if settings_service:\n+            xblock_settings = settings_service.get_settings_bucket(self)\n+            if xblock_settings and setting in xblock_settings:\n+                result = xblock_settings[setting]\n+        return result\n+\n+\n+class AuthXBlockMixin(SettingsMixin, ProjectAPIXBlockMixin):\n+\n+    _DEFAULT_TA_ROLE = ('assistant',)\n+\n+    _SEE_DASHBOARD_ROLE_PERMS = \"see_dashboard_role_perms\"\n+    _SEE_DASHBOARD_FOR_ALL_ORGS_ROLE_PERMS = \"see_dashboard_for_all_orgs_perms\"\n+    _TA_ROLE = 'ta_roles'\n+\n+    @property\n+    def see_dashboard_role_perms(self):\n+        \"\"\"\n+        :return: Returns a list of group names, user needs to be a member of\n+                 single group from this list to access dashboard.\n+                 Additionally he will see this dashboard\n+                 filtered so he only sees students from organisations he\n+                 belongs to.\n+        :rtype: Iterable[str]\n+        \"\"\"\n+        return self._get_setting(self._SEE_DASHBOARD_ROLE_PERMS, [])\n+\n+    @property\n+    def see_dashboard_for_all_orgs_perms(self):\n+        \"\"\"\n+        :return: Returns a list of group names, user needs to be a member of\n+                 single group from this list to access dashboard.\n+                 Members of these roles will see dashboard with users\n+                 from all organisations.\n+        :rtype: Iterable[str]\n+        \"\"\"\n+        return self._get_setting(self._SEE_DASHBOARD_FOR_ALL_ORGS_ROLE_PERMS, [])\n+\n+    @property\n+    def ta_roles(self):\n+        \"\"\"\n+\n+        .. note:\n+\n+            This returns different thing than self.see_dashboard_for_all_orgs\n+            this returns a **course** role, and rest contains a user group.\n+\n+        :return: Returns a list of group names. Normally to access a group work\n+                 view user will need to belong to a team. If user is a member\n+                 of this group he will be able to access group work for every\n+                 group work team.\n+        :rtype: Iterable[str]\n+        \"\"\"\n+        return self._get_setting(self._TA_ROLE, self._DEFAULT_TA_ROLE)\n+\n+    def can_access_dashboard(self, user_id):\n+        \"\"\"\n+        :param user_id:\n+        :return: True if user can access dashboard.\n+        \"\"\"\n+        user_groups = self._user_groups(user_id)\n+        return bool(user_groups & self._access_dashboard_roles)\n+\n+    def check_dashboard_access(self, user_id):\n+        \"\"\"\n+        :return: None\n+        :raise GroupworkAccessDeniedError: If user can't access dashboard\n+        \"\"\"\n+        if not self.can_access_dashboard(user_id):\n+            raise GroupworkAccessDeniedError(\"User can't access dashboard\")\n+\n+    def is_user_ta(self, user_id, course_id):\n+        \"\"\"\n+        :return: True if user is a TA for a gven course\n+        \"\"\"\n+\n+        granted_roles = {r[\"role\"] for r in self.project_api.get_user_roles_for_course(user_id, course_id)}\n+        allowed_roles = set(self.ta_roles)\n+        return bool(allowed_roles & granted_roles)\n+\n+    def check_outsider_allowed(self, user_id, course_id):\n+        \"\"\"\n+        :return: None\n+        :raise GroupworkAccessDeniedError: If user can't access a groupwork item\n+        if he is not part of the team.\n+        \"\"\"\n+        if not self.is_user_ta(user_id, course_id):\n+            raise GroupworkAccessDeniedError(\"User can't access this group work\")\n+\n+    def get_organisation_filter_for_user(self, user_id, additional_filter=None):\n+        \"\"\"\n+        :param Iterable[int] additional_filter:\n+            Iterable of organization ids that are filtered additionally.\n+        :return: Returns object that can be used if user_id has access to\n+                 an organisation. This callable returns bool an expects to be\n+                 called with organization id.\n+        :rtype: Callable[[int], bool]\n+        \"\"\"\n+        if self._can_user_access_all_orgs(user_id):\n+            allowed_org_ids = None\n+        else:\n+            allowed_orgs = self.project_api.get_user_organizations(user_id)\n+            allowed_org_ids = (org['id'] for org in allowed_orgs)\n+        return self.OrganizationFilterObject(self, user_id, allowed_org_ids, additional_filter)\n+\n+    class OrganizationFilterObject(object):\n+\n+        \"\"\"\n+        A class that checks whether an user can access an organisation.\n+\n+        Contains two sets: one with organisations user has access to, and second\n+        with organisations that user has explicitily filtered for.\n+\n+        Value None means \"all organisations\" --- since there can be a large\n+        number of organisations, we avoid keeping \"all organisations\" that way.\n+        \"\"\"\n+\n+        def __init__(self, parent, user_id, allowed_org_ids, filter_org_ids=None):\n+            self.parent = parent\n+            self.user_id = user_id\n+            self.filter_org_ids = set(filter_org_ids) if filter_org_ids is not None else None\n+            \"\"\"\n+            :type: set[int] or None\n+            \"\"\"  # pylint: disable=pointless-string-statement\n+            self.allowed_org_ids = set(allowed_org_ids) if allowed_org_ids is not None else None\n+            \"\"\"\n+            :type: set[int] or None\n+            \"\"\"  # pylint: disable=pointless-string-statement\n+\n+        def can_user_see_another_user(self, user_id):","path":"group_project_v2/mixins.py","position":158,"original_position":158,"commit_id":"a0107e1ff34d0c031edd0ac9dbd0db433463218b","original_commit_id":"a0107e1ff34d0c031edd0ac9dbd0db433463218b","user":{"login":"e-kolpakov","id":3330048,"avatar_url":"https://avatars.githubusercontent.com/u/3330048?v=3","gravatar_id":"","url":"https://api.github.com/users/e-kolpakov","html_url":"https://github.com/e-kolpakov","followers_url":"https://api.github.com/users/e-kolpakov/followers","following_url":"https://api.github.com/users/e-kolpakov/following{/other_user}","gists_url":"https://api.github.com/users/e-kolpakov/gists{/gist_id}","starred_url":"https://api.github.com/users/e-kolpakov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/e-kolpakov/subscriptions","organizations_url":"https://api.github.com/users/e-kolpakov/orgs","repos_url":"https://api.github.com/users/e-kolpakov/repos","events_url":"https://api.github.com/users/e-kolpakov/events{/privacy}","received_events_url":"https://api.github.com/users/e-kolpakov/received_events","type":"User","site_admin":false},"body":"@jbzdak nit: I believe `can_see_another_user` would be slightly less confusing. Also see \"can_see vs. can_access\" above.","created_at":"2016-02-12T14:00:25Z","updated_at":"2016-02-12T14:00:25Z","html_url":"https://github.com/open-craft/xblock-group-project-v2/pull/85#discussion_r52743703","pull_request_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85","_links":{"self":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/comments/52743703"},"html":{"href":"https://github.com/open-craft/xblock-group-project-v2/pull/85#discussion_r52743703"},"pull_request":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85"}}},"pull_request":{"url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85","id":58931075,"html_url":"https://github.com/open-craft/xblock-group-project-v2/pull/85","diff_url":"https://github.com/open-craft/xblock-group-project-v2/pull/85.diff","patch_url":"https://github.com/open-craft/xblock-group-project-v2/pull/85.patch","issue_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/85","number":85,"state":"open","locked":false,"title":"OC-1287 Filter by company","user":{"login":"jbzdak","id":112872,"avatar_url":"https://avatars.githubusercontent.com/u/112872?v=3","gravatar_id":"","url":"https://api.github.com/users/jbzdak","html_url":"https://github.com/jbzdak","followers_url":"https://api.github.com/users/jbzdak/followers","following_url":"https://api.github.com/users/jbzdak/following{/other_user}","gists_url":"https://api.github.com/users/jbzdak/gists{/gist_id}","starred_url":"https://api.github.com/users/jbzdak/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbzdak/subscriptions","organizations_url":"https://api.github.com/users/jbzdak/orgs","repos_url":"https://api.github.com/users/jbzdak/repos","events_url":"https://api.github.com/users/jbzdak/events{/privacy}","received_events_url":"https://api.github.com/users/jbzdak/received_events","type":"User","site_admin":false},"body":"What is done: \r\n- [x] Client Id is sent by GET parameter by GWv2\r\n- [x] We have a very simple graying out logic for graying out filtered users \r\n- [x] Hiding groups made entirely from people from the other companies \r\n- [x] Filtering done for Company Admins\r\n- [x] Company Combo-Box always show all companies, but it should only show companies participaing in designed course/programme\r\n- [x] Fix tests\r\n\r\nWhat should be done \r\n- [ ] Add tests \r\n\r\n**Post-internal review todos**\r\n- [ ] Squash commits \r\n- [ ] Get :+1: from the devops for config changes\r\n\r\n**Major changes in XBlock logic**\r\n\r\n* User needs to have a specific role to access dashboard at all\r\n* Company admins will have the detail dashboard pre-filtered by company, this person is administering, which means he will only have access to groups that contain no students from this company. This filter can't be taken down. \r\n\r\n**Configuration changes** \r\n\r\nUse following ``XBLOCK_SETTINGS``: \r\n\r\n\t\"XBLOCK_SETTINGS\": {\r\n\t\t\"group_project_v2\": {\r\n\t\t    \"dashboard_details_url\": \"/admin/workgroup/dashboard/programs/{program_id}/courses/{course_id}/projects/{project_id}/details?activate_block_id={activity_id}\",\r\n\t\t    \"ta_review_url\": \"/courses/{course_id}/group_work/{group_id}?activate_block_id={activate_block_id}\",\r\n\t\t \"see_dashboard_for_all_orgs_perms\": [\"mcka_role_mcka_admin\"],\r\n\t\t \"see_dashboard_role_perms\": [\"mcka_role_client_admin\", \"mcka_role_internal_admin\"],\r\n\t\t \"ta_roles\": [\"assistant\"]\r\n\t\t}\r\n\t}, \r\n\r\n\r\nTesting Instructions: \r\n\r\n**Common steps**\r\n0. Download Apros from this branch: https://github.com/mckinseyacademy/mcka_apros/pull/1308\r\n1. Create 4 clients, Client1, Client2, Client3. Client4 \r\n2. Associate Client1, 2 and 3 with a program with Group Work\r\n3. Create three users for each Client (except for Client4 for which it is not needed)\r\n4. Assign Clients to course with Group Work\r\n5. Following Groups: \r\n - 2 students from Client 1 (Group 1) \r\n - 2 students from Client 2 and a student from Client 1 (Group 2) \r\n6. Set up a student from Client 2 as a company admin/internal admin for that company\r\n\r\n**Combo box behavior**\r\n\r\n* Note that Client 4 organisation is missing form the Combo box (as combo box contains all organisations that take part in this program). \r\n\r\n**Filtering for mcka_admin**\r\n1. Login as mcka_admin_user\r\n2. Go to detail dashboard and observe following behavior: \r\n\r\n  - When you select Client 3 all work groups are hidden and there is a following message: \"All workgroups have been filtered by the company filter.\"\r\n  - When you select Client 2 students one of the workgroups is filtered out, and students from Client1 are grayed out.\r\n  - When you select All companies students are not grayed out at all \r\n  - When you select Client 2 Group 1 is hidden \r\n  - When you select Client 1 No groups are hidden\r\n\r\nNote dashboard detail url called by apros (it looks something like that on my system): ``http://apros.mcka.local/courses/FooX/FooX/v3/xblock/i4x://FooX/FooX/gp-v2-project/41fe8cae0614470c9aeb72bd078b0348/view/dashboard_detail_view?activate_block_id=i4x%3A%2F%2FFooX%2FFooX%2Fgp-v2-activity%2F9f956e0072be43ac9366836d17d57a12&client_filter_id=2&_=1455270983305``\r\n\r\n**Check that dashboard is hidden for low privileged users**\r\n\r\n1. Login as as student user\r\n2. Enter URL you noted in last step. \r\n3. Note that JSON contents are different, and contain: \"Outsider Denied Access: User can&#39;t access dashboard\" \r\n\r\n**Behavior for company admins**\r\n\r\n1. Log in as a company admin for Company 2\r\n2. Go to details view \r\n3. Notice that Group View is filtered to contain group with Company 2 and there is no combo-box filter. \r\n4. Enter URL you noted in two steps ago. Change filter ID in such a way that we filter using a different id than those of company 2, note that html contains: \"All work groups have been filtered by the company filter.\" --- that is no groups are visible. \r\n\r\n**Test sorting**\r\n\r\n1. Fill a Peer Review for using a student for Group 2. Note that he has a green checkmark in dashboard. \r\n2. Filter dashboard using both Client 1 and Client 2, note that despite being sorted up or down user still has a green checkmark. ","created_at":"2016-02-10T18:18:43Z","updated_at":"2016-02-12T14:00:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6e0950460a5f62320132ca73015d357e3ae936f4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85/commits","review_comments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85/comments","review_comment_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/85/comments","statuses_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/statuses/a0107e1ff34d0c031edd0ac9dbd0db433463218b","head":{"label":"open-craft:jbzdak/add-company-filter-to-detail-view","ref":"jbzdak/add-company-filter-to-detail-view","sha":"a0107e1ff34d0c031edd0ac9dbd0db433463218b","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":36354647,"name":"xblock-group-project-v2","full_name":"open-craft/xblock-group-project-v2","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/xblock-group-project-v2","description":"Group Project XBlock v2","fork":false,"url":"https://api.github.com/repos/open-craft/xblock-group-project-v2","forks_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/forks","keys_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/teams","hooks_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/hooks","issue_events_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/events","assignees_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/tags","blobs_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/languages","stargazers_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/stargazers","contributors_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/contributors","subscribers_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/subscribers","subscription_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/subscription","commits_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/merges","archive_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/downloads","issues_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/releases{/id}","deployments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/deployments","created_at":"2015-05-27T08:45:35Z","updated_at":"2016-01-12T07:02:57Z","pushed_at":"2016-02-12T13:13:22Z","git_url":"git://github.com/open-craft/xblock-group-project-v2.git","ssh_url":"git@github.com:open-craft/xblock-group-project-v2.git","clone_url":"https://github.com/open-craft/xblock-group-project-v2.git","svn_url":"https://github.com/open-craft/xblock-group-project-v2","homepage":null,"size":1816,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":3,"default_branch":"master"}},"base":{"label":"open-craft:master","ref":"master","sha":"73dbc78be4808fe7f237894bd9d2de212bb22362","user":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"repo":{"id":36354647,"name":"xblock-group-project-v2","full_name":"open-craft/xblock-group-project-v2","owner":{"login":"open-craft","id":7414786,"avatar_url":"https://avatars.githubusercontent.com/u/7414786?v=3","gravatar_id":"","url":"https://api.github.com/users/open-craft","html_url":"https://github.com/open-craft","followers_url":"https://api.github.com/users/open-craft/followers","following_url":"https://api.github.com/users/open-craft/following{/other_user}","gists_url":"https://api.github.com/users/open-craft/gists{/gist_id}","starred_url":"https://api.github.com/users/open-craft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/open-craft/subscriptions","organizations_url":"https://api.github.com/users/open-craft/orgs","repos_url":"https://api.github.com/users/open-craft/repos","events_url":"https://api.github.com/users/open-craft/events{/privacy}","received_events_url":"https://api.github.com/users/open-craft/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/open-craft/xblock-group-project-v2","description":"Group Project XBlock v2","fork":false,"url":"https://api.github.com/repos/open-craft/xblock-group-project-v2","forks_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/forks","keys_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/teams","hooks_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/hooks","issue_events_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/events{/number}","events_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/events","assignees_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/assignees{/user}","branches_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/branches{/branch}","tags_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/tags","blobs_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/refs{/sha}","trees_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/statuses/{sha}","languages_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/languages","stargazers_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/stargazers","contributors_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/contributors","subscribers_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/subscribers","subscription_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/subscription","commits_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/commits{/sha}","git_commits_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/git/commits{/sha}","comments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/comments{/number}","issue_comment_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/comments{/number}","contents_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/contents/{+path}","compare_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/merges","archive_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/downloads","issues_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues{/number}","pulls_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls{/number}","milestones_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/milestones{/number}","notifications_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/labels{/name}","releases_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/releases{/id}","deployments_url":"https://api.github.com/repos/open-craft/xblock-group-project-v2/deployments","created_at":"2015-05-27T08:45:35Z","updated_at":"2016-01-12T07:02:57Z","pushed_at":"2016-02-12T13:13:22Z","git_url":"git://github.com/open-craft/xblock-group-project-v2.git","ssh_url":"git@github.com:open-craft/xblock-group-project-v2.git","clone_url":"https://github.com/open-craft/xblock-group-project-v2.git","svn_url":"https://github.com/open-craft/xblock-group-project-v2","homepage":null,"size":1816,"stargazers_count":3,"watchers_count":3,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85"},"html":{"href":"https://github.com/open-craft/xblock-group-project-v2/pull/85"},"issue":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/85"},"comments":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/issues/85/comments"},"review_comments":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85/comments"},"review_comment":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/pulls/85/commits"},"statuses":{"href":"https://api.github.com/repos/open-craft/xblock-group-project-v2/statuses/a0107e1ff34d0c031edd0ac9dbd0db433463218b"}}}}