{"action":"created","comment":{"url":"https://api.github.com/repos/mitodl/micromasters/pulls/comments/79822278","id":79822278,"diff_hunk":"@@ -1,24 +1,229 @@\n \"\"\"\n Views for financialaid\n \"\"\"\n+import json\n+\n+from django.conf import settings\n+from django.contrib.auth.mixins import UserPassesTestMixin\n+from django.db.models import F\n+from django.views.generic import ListView\n from rest_framework.authentication import SessionAuthentication\n-from rest_framework.generics import CreateAPIView\n+from rest_framework.generics import (\n+    CreateAPIView,\n+    get_object_or_404\n+)\n from rest_framework.permissions import IsAuthenticated\n+from rolepermissions.verifications import has_object_permission\n \n-from financialaid.serializers import FinancialAidSerializer\n+from courses.models import Program, CourseRun\n+from ecommerce.models import CoursePrice\n+from financialaid.models import (\n+    FinancialAid,\n+    FinancialAidStatus,\n+    TierProgram\n+)\n+from financialaid.serializers import IncomeValidationSerializer\n+from roles.roles import Permissions\n+from ui.views import get_bundle_url\n \n \n class IncomeValidationView(CreateAPIView):\n     \"\"\"\n     View for income validation API. Takes income and currency, then determines whether review\n     is necessary, and if not, sets the appropriate tier for personalized pricing.\n     \"\"\"\n-    serializer_class = FinancialAidSerializer\n+    serializer_class = IncomeValidationSerializer\n     authentication_classes = (SessionAuthentication, )\n     permission_classes = (IsAuthenticated, )\n \n-    def get_queryset(self):\n+    def get_queryset(self):  # pragma: no cover\n         \"\"\"\n-        Used for returning the view, which hasn't been defined yet.\n+        Allows the DRF helper pages to load - not available in production\n         \"\"\"\n         return None\n+\n+\n+class ReviewFinancialAidView(UserPassesTestMixin, ListView):\n+    \"\"\"\n+    View for reviewing financial aid requests.\n+    Note: In the future, it may be worth factoring out the code for sorting into its own subclass of ListView\n+    \"\"\"\n+    paginate_by = 10\n+    context_object_name = \"financial_aid_objects\"\n+    template_name = \"review_financial_aid.html\"\n+    # If user doesn't pass test_func, raises exception instead of redirecting to login url\n+    raise_exception = True\n+    # Used to modify queryset and in context\n+    selected_status = None\n+    program = None\n+    # Used for sorting\n+    sort_field = None\n+    sort_direction = \"\"\n+    sort_field_info = None\n+    sort_fields = {\n+        \"first_name\": {\n+            \"display\": \"First Name\"\n+        },\n+        \"last_name\": {\n+            \"display\": \"Last Name\"\n+        },\n+        \"location\": {\n+            \"display\": \"Location\"\n+        },\n+        \"adjusted_cost\": {\n+            \"display\": \"Adjusted Cost\"\n+        },\n+        \"reported_income\": {\n+            \"display\": \"Reported Income\"\n+        },\n+    }\n+    sort_field_mappings = {\n+        \"first_name\": \"user__profile__first_name\",\n+        \"last_name\": \"user__profile__last_name\",\n+        \"location\": \"user__profile__city\",\n+        \"adjusted_cost\": \"adjusted_price\",\n+        \"reported_income\": \"income_usd\",\n+    }\n+    default_sort_field = \"first_name\"\n+\n+    def test_func(self):\n+        \"\"\"\n+        Validate user permissions (Analogous to permissions_classes for DRF)\n+        \"\"\"\n+        self.program = get_object_or_404(Program, id=self.kwargs.get(\"program_id\", None))\n+        return has_object_permission(Permissions.CAN_EDIT_FINANCIAL_AID, self.request.user, self.program)\n+\n+    def get_context_data(self, **kwargs):\n+        \"\"\"\n+        Gets context for view\n+        \"\"\"\n+        context = super().get_context_data(**kwargs)\n+\n+        # Constants required in view\n+        context[\"selected_status\"] = self.selected_status\n+        context[\"current_program_id\"] = self.program.id\n+\n+        # Create ordered list of (financial aid status, financial message)\n+        messages = FinancialAidStatus.STATUS_MESSAGES_DICT\n+        message_order = (\n+            FinancialAidStatus.PENDING_MANUAL_APPROVAL,\n+            FinancialAidStatus.APPROVED,\n+            FinancialAidStatus.REJECTED,\n+            FinancialAidStatus.AUTO_APPROVED\n+        )\n+        context[\"financial_aid_statuses\"] = (\n+            (status, \"Show: {message}\".format(message=messages[status]))\n+            for status in message_order\n+        )\n+\n+        # Get sort field information\n+        sort_link_order = (\n+            \"first_name\",\n+            \"last_name\",\n+            \"location\",\n+            \"adjusted_cost\",\n+            \"reported_income\",\n+        )\n+        new_sort_direction = \"\" if self.sort_direction == \"-\" else \"-\"\n+        context[\"sort_field_info\"] = (\n+            {\n+                # For appending the sort_by get param on url\n+                \"sort_field\": \"{sort_direction}{sort_field}\".format(\n+                    # If this field is our current sort field, we want to toggle the sort direction, else default \"\"\n+                    sort_direction=new_sort_direction if field == self.sort_field else \"\",\n+                    sort_field=field\n+                ),\n+                # If this field is the current sort field, we want to indicate the current sort direction\n+                \"direction_display\": self.sort_direction if field == self.sort_field else None,\n+                \"display\": self.sort_fields[field][\"display\"]\n+            }\n+            for field in sort_link_order\n+        )\n+\n+        # Required for styling\n+        context[\"style_src\"] = get_bundle_url(self.request, \"style.js\")\n+        context[\"dashboard_src\"] = get_bundle_url(self.request, \"dashboard.js\")\n+        js_settings = {\n+            \"gaTrackingID\": settings.GA_TRACKING_ID,\n+            \"reactGaDebug\": settings.REACT_GA_DEBUG,\n+            \"authenticated\": not self.request.user.is_anonymous(),\n+            \"edx_base_url\": settings.EDXORG_BASE_URL,\n+        }\n+        context[\"js_settings_json\"] = json.dumps(js_settings)\n+        return context\n+\n+    def get_queryset(self):\n+        \"\"\"\n+        Gets queryset for ListView to return to view\n+        \"\"\"\n+        # Filter by availability\n+        financial_aids = FinancialAid.objects.filter(\n+            tier_program__program__live=True,\n+            tier_program__program__financial_aid_availability=True\n+        )\n+\n+        # Filter by program (self.program set in test_func())\n+        financial_aids = financial_aids.filter(\n+            tier_program__program=self.program,\n+        )\n+\n+        # Filter by status\n+        self.selected_status = self.kwargs.get(\"status\", None)\n+        if self.selected_status is None or self.selected_status not in FinancialAidStatus.ALL_STATUSES:\n+            self.selected_status = FinancialAidStatus.PENDING_MANUAL_APPROVAL\n+        financial_aids = financial_aids.filter(status=self.selected_status)\n+\n+        # Sort by field\n+        self.sort_field = self.request.GET.get(\"sort_by\", self.default_sort_field)\n+        if self.sort_field.startswith(\"-\"):\n+            self.sort_field = self.sort_field[1:]\n+            # Defined above: self.sort_direction = \"\"\n+            self.sort_direction = \"-\"\n+        if self.sort_field not in self.sort_fields:\n+            self.sort_field = self.default_sort_field\n+            self.sort_direction = \"\"\n+        financial_aids = financial_aids.order_by(\n+            \"{sort_direction}{sort_field}\".format(\n+                sort_direction=self.sort_direction,\n+                sort_field=self.sort_field_mappings.get(self.sort_field, self.sort_field)\n+            )\n+        )\n+\n+        # Add adjusted cost and TierPrograms valid for selection for each FinancialAid object\n+        # Note: iterating through this queryset, if large, can be very costly in terms of memory/time,\n+        # but it is done here to simplify the templates.\n+        # Get program ids and associated tier programs\n+        program_ids = Program.objects.filter(\n+            live=True,\n+            financial_aid_availability=True\n+        ).values_list(\n+            \"id\",\n+            flat=True\n+        )\n+        # Get course price to calculate adjusted cost\n+        # Note: This implementation of retrieving a course price is a naive lookup that assumes\n+        # all course runs and courses will be the same price for the foreseeable future,\n+        # irrespective of the program. Therefore we can just take the price from any currently\n+        # enroll-able course run.\n+        course_price = CoursePrice.objects.filter(\n+            is_valid=True,\n+            course_run__in=CourseRun.objects.filter(\n+                course__program_id=self.program.id\n+            ).filter(\n+                CourseRun.get_active_enrollment_queryset()","path":"financialaid/views.py","position":null,"original_position":218,"commit_id":"88a39b6b06e6670f308f5115488ec0425b5684ff","original_commit_id":"a78d8b5df5151863708a5ebdf0f058fa3c62908f","user":{"login":"noisecapella","id":863262,"avatar_url":"https://avatars.githubusercontent.com/u/863262?v=3","gravatar_id":"","url":"https://api.github.com/users/noisecapella","html_url":"https://github.com/noisecapella","followers_url":"https://api.github.com/users/noisecapella/followers","following_url":"https://api.github.com/users/noisecapella/following{/other_user}","gists_url":"https://api.github.com/users/noisecapella/gists{/gist_id}","starred_url":"https://api.github.com/users/noisecapella/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/noisecapella/subscriptions","organizations_url":"https://api.github.com/users/noisecapella/orgs","repos_url":"https://api.github.com/users/noisecapella/repos","events_url":"https://api.github.com/users/noisecapella/events{/privacy}","received_events_url":"https://api.github.com/users/noisecapella/received_events","type":"User","site_admin":false},"body":"Also, in general do not worry about the little performance gains here and there. We should write clean code first and optimize only if there's an immediate need for it. There will probably never be greater than say, 10000 course runs over the life of this system, and at that level it doesn't really matter how that query is filtered as long as we avoid things like n+1 selects.\r\n\r\nI know, famous last words, but if performance problems come up it will be a long time in the future and we can deal with optimizing then.","created_at":"2016-09-21T12:35:37Z","updated_at":"2016-09-21T12:35:37Z","html_url":"https://github.com/mitodl/micromasters/pull/1071#discussion_r79822278","pull_request_url":"https://api.github.com/repos/mitodl/micromasters/pulls/1071","_links":{"self":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/comments/79822278"},"html":{"href":"https://github.com/mitodl/micromasters/pull/1071#discussion_r79822278"},"pull_request":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/1071"}}},"pull_request":{"url":"https://api.github.com/repos/mitodl/micromasters/pulls/1071","id":85902897,"html_url":"https://github.com/mitodl/micromasters/pull/1071","diff_url":"https://github.com/mitodl/micromasters/pull/1071.diff","patch_url":"https://github.com/mitodl/micromasters/pull/1071.patch","issue_url":"https://api.github.com/repos/mitodl/micromasters/issues/1071","number":1071,"state":"open","locked":false,"title":"Implemented backbone for review financial aid page","user":{"login":"alvinsiu","id":1454606,"avatar_url":"https://avatars.githubusercontent.com/u/1454606?v=3","gravatar_id":"","url":"https://api.github.com/users/alvinsiu","html_url":"https://github.com/alvinsiu","followers_url":"https://api.github.com/users/alvinsiu/followers","following_url":"https://api.github.com/users/alvinsiu/following{/other_user}","gists_url":"https://api.github.com/users/alvinsiu/gists{/gist_id}","starred_url":"https://api.github.com/users/alvinsiu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alvinsiu/subscriptions","organizations_url":"https://api.github.com/users/alvinsiu/orgs","repos_url":"https://api.github.com/users/alvinsiu/repos","events_url":"https://api.github.com/users/alvinsiu/events{/privacy}","received_events_url":"https://api.github.com/users/alvinsiu/received_events","type":"User","site_admin":false},"body":"#### What are the relevant tickets?\r\n#1045 \r\n\r\n#### What's this PR do?\r\nImplements the backbone template and view for reviewing financial aid applications.  This PR does not implement any of the functionality from the page (aside from pagination and sorting).\r\n\r\n#### Where should the reviewer start?\r\n\r\n#### How should this be manually tested?\r\n\r\n#### Any background context you want to provide?\r\n\r\n#### Screenshots (if appropriate)\r\n\r\n#### What GIF best describes this PR or how it makes you feel?\r\n","created_at":"2016-09-20T02:50:40Z","updated_at":"2016-09-21T12:35:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0d3b36a4b6e46e177b408798763a22dba2e4f581","assignee":{"login":"noisecapella","id":863262,"avatar_url":"https://avatars.githubusercontent.com/u/863262?v=3","gravatar_id":"","url":"https://api.github.com/users/noisecapella","html_url":"https://github.com/noisecapella","followers_url":"https://api.github.com/users/noisecapella/followers","following_url":"https://api.github.com/users/noisecapella/following{/other_user}","gists_url":"https://api.github.com/users/noisecapella/gists{/gist_id}","starred_url":"https://api.github.com/users/noisecapella/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/noisecapella/subscriptions","organizations_url":"https://api.github.com/users/noisecapella/orgs","repos_url":"https://api.github.com/users/noisecapella/repos","events_url":"https://api.github.com/users/noisecapella/events{/privacy}","received_events_url":"https://api.github.com/users/noisecapella/received_events","type":"User","site_admin":false},"assignees":[{"login":"noisecapella","id":863262,"avatar_url":"https://avatars.githubusercontent.com/u/863262?v=3","gravatar_id":"","url":"https://api.github.com/users/noisecapella","html_url":"https://github.com/noisecapella","followers_url":"https://api.github.com/users/noisecapella/followers","following_url":"https://api.github.com/users/noisecapella/following{/other_user}","gists_url":"https://api.github.com/users/noisecapella/gists{/gist_id}","starred_url":"https://api.github.com/users/noisecapella/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/noisecapella/subscriptions","organizations_url":"https://api.github.com/users/noisecapella/orgs","repos_url":"https://api.github.com/users/noisecapella/repos","events_url":"https://api.github.com/users/noisecapella/events{/privacy}","received_events_url":"https://api.github.com/users/noisecapella/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/mitodl/micromasters/pulls/1071/commits","review_comments_url":"https://api.github.com/repos/mitodl/micromasters/pulls/1071/comments","review_comment_url":"https://api.github.com/repos/mitodl/micromasters/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mitodl/micromasters/issues/1071/comments","statuses_url":"https://api.github.com/repos/mitodl/micromasters/statuses/88a39b6b06e6670f308f5115488ec0425b5684ff","head":{"label":"mitodl:zagaran/reviewfinancialaid","ref":"zagaran/reviewfinancialaid","sha":"88a39b6b06e6670f308f5115488ec0425b5684ff","user":{"login":"mitodl","id":7918516,"avatar_url":"https://avatars.githubusercontent.com/u/7918516?v=3","gravatar_id":"","url":"https://api.github.com/users/mitodl","html_url":"https://github.com/mitodl","followers_url":"https://api.github.com/users/mitodl/followers","following_url":"https://api.github.com/users/mitodl/following{/other_user}","gists_url":"https://api.github.com/users/mitodl/gists{/gist_id}","starred_url":"https://api.github.com/users/mitodl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitodl/subscriptions","organizations_url":"https://api.github.com/users/mitodl/orgs","repos_url":"https://api.github.com/users/mitodl/repos","events_url":"https://api.github.com/users/mitodl/events{/privacy}","received_events_url":"https://api.github.com/users/mitodl/received_events","type":"Organization","site_admin":false},"repo":{"id":52919185,"name":"micromasters","full_name":"mitodl/micromasters","owner":{"login":"mitodl","id":7918516,"avatar_url":"https://avatars.githubusercontent.com/u/7918516?v=3","gravatar_id":"","url":"https://api.github.com/users/mitodl","html_url":"https://github.com/mitodl","followers_url":"https://api.github.com/users/mitodl/followers","following_url":"https://api.github.com/users/mitodl/following{/other_user}","gists_url":"https://api.github.com/users/mitodl/gists{/gist_id}","starred_url":"https://api.github.com/users/mitodl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitodl/subscriptions","organizations_url":"https://api.github.com/users/mitodl/orgs","repos_url":"https://api.github.com/users/mitodl/repos","events_url":"https://api.github.com/users/mitodl/events{/privacy}","received_events_url":"https://api.github.com/users/mitodl/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mitodl/micromasters","description":"Portal for learners and course teams to access MITx micromasters programs: https://goo.gl/tsUTSO","fork":false,"url":"https://api.github.com/repos/mitodl/micromasters","forks_url":"https://api.github.com/repos/mitodl/micromasters/forks","keys_url":"https://api.github.com/repos/mitodl/micromasters/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mitodl/micromasters/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mitodl/micromasters/teams","hooks_url":"https://api.github.com/repos/mitodl/micromasters/hooks","issue_events_url":"https://api.github.com/repos/mitodl/micromasters/issues/events{/number}","events_url":"https://api.github.com/repos/mitodl/micromasters/events","assignees_url":"https://api.github.com/repos/mitodl/micromasters/assignees{/user}","branches_url":"https://api.github.com/repos/mitodl/micromasters/branches{/branch}","tags_url":"https://api.github.com/repos/mitodl/micromasters/tags","blobs_url":"https://api.github.com/repos/mitodl/micromasters/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mitodl/micromasters/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mitodl/micromasters/git/refs{/sha}","trees_url":"https://api.github.com/repos/mitodl/micromasters/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mitodl/micromasters/statuses/{sha}","languages_url":"https://api.github.com/repos/mitodl/micromasters/languages","stargazers_url":"https://api.github.com/repos/mitodl/micromasters/stargazers","contributors_url":"https://api.github.com/repos/mitodl/micromasters/contributors","subscribers_url":"https://api.github.com/repos/mitodl/micromasters/subscribers","subscription_url":"https://api.github.com/repos/mitodl/micromasters/subscription","commits_url":"https://api.github.com/repos/mitodl/micromasters/commits{/sha}","git_commits_url":"https://api.github.com/repos/mitodl/micromasters/git/commits{/sha}","comments_url":"https://api.github.com/repos/mitodl/micromasters/comments{/number}","issue_comment_url":"https://api.github.com/repos/mitodl/micromasters/issues/comments{/number}","contents_url":"https://api.github.com/repos/mitodl/micromasters/contents/{+path}","compare_url":"https://api.github.com/repos/mitodl/micromasters/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mitodl/micromasters/merges","archive_url":"https://api.github.com/repos/mitodl/micromasters/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mitodl/micromasters/downloads","issues_url":"https://api.github.com/repos/mitodl/micromasters/issues{/number}","pulls_url":"https://api.github.com/repos/mitodl/micromasters/pulls{/number}","milestones_url":"https://api.github.com/repos/mitodl/micromasters/milestones{/number}","notifications_url":"https://api.github.com/repos/mitodl/micromasters/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mitodl/micromasters/labels{/name}","releases_url":"https://api.github.com/repos/mitodl/micromasters/releases{/id}","deployments_url":"https://api.github.com/repos/mitodl/micromasters/deployments","created_at":"2016-03-01T23:53:17Z","updated_at":"2016-08-19T01:46:48Z","pushed_at":"2016-09-21T12:02:54Z","git_url":"git://github.com/mitodl/micromasters.git","ssh_url":"git@github.com:mitodl/micromasters.git","clone_url":"https://github.com/mitodl/micromasters.git","svn_url":"https://github.com/mitodl/micromasters","homepage":"","size":12753,"stargazers_count":5,"watchers_count":5,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":156,"forks":3,"open_issues":156,"watchers":5,"default_branch":"master"}},"base":{"label":"mitodl:master","ref":"master","sha":"d45a13b44162660f1fa32938a200eec59a790c27","user":{"login":"mitodl","id":7918516,"avatar_url":"https://avatars.githubusercontent.com/u/7918516?v=3","gravatar_id":"","url":"https://api.github.com/users/mitodl","html_url":"https://github.com/mitodl","followers_url":"https://api.github.com/users/mitodl/followers","following_url":"https://api.github.com/users/mitodl/following{/other_user}","gists_url":"https://api.github.com/users/mitodl/gists{/gist_id}","starred_url":"https://api.github.com/users/mitodl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitodl/subscriptions","organizations_url":"https://api.github.com/users/mitodl/orgs","repos_url":"https://api.github.com/users/mitodl/repos","events_url":"https://api.github.com/users/mitodl/events{/privacy}","received_events_url":"https://api.github.com/users/mitodl/received_events","type":"Organization","site_admin":false},"repo":{"id":52919185,"name":"micromasters","full_name":"mitodl/micromasters","owner":{"login":"mitodl","id":7918516,"avatar_url":"https://avatars.githubusercontent.com/u/7918516?v=3","gravatar_id":"","url":"https://api.github.com/users/mitodl","html_url":"https://github.com/mitodl","followers_url":"https://api.github.com/users/mitodl/followers","following_url":"https://api.github.com/users/mitodl/following{/other_user}","gists_url":"https://api.github.com/users/mitodl/gists{/gist_id}","starred_url":"https://api.github.com/users/mitodl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitodl/subscriptions","organizations_url":"https://api.github.com/users/mitodl/orgs","repos_url":"https://api.github.com/users/mitodl/repos","events_url":"https://api.github.com/users/mitodl/events{/privacy}","received_events_url":"https://api.github.com/users/mitodl/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mitodl/micromasters","description":"Portal for learners and course teams to access MITx micromasters programs: https://goo.gl/tsUTSO","fork":false,"url":"https://api.github.com/repos/mitodl/micromasters","forks_url":"https://api.github.com/repos/mitodl/micromasters/forks","keys_url":"https://api.github.com/repos/mitodl/micromasters/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mitodl/micromasters/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mitodl/micromasters/teams","hooks_url":"https://api.github.com/repos/mitodl/micromasters/hooks","issue_events_url":"https://api.github.com/repos/mitodl/micromasters/issues/events{/number}","events_url":"https://api.github.com/repos/mitodl/micromasters/events","assignees_url":"https://api.github.com/repos/mitodl/micromasters/assignees{/user}","branches_url":"https://api.github.com/repos/mitodl/micromasters/branches{/branch}","tags_url":"https://api.github.com/repos/mitodl/micromasters/tags","blobs_url":"https://api.github.com/repos/mitodl/micromasters/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mitodl/micromasters/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mitodl/micromasters/git/refs{/sha}","trees_url":"https://api.github.com/repos/mitodl/micromasters/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mitodl/micromasters/statuses/{sha}","languages_url":"https://api.github.com/repos/mitodl/micromasters/languages","stargazers_url":"https://api.github.com/repos/mitodl/micromasters/stargazers","contributors_url":"https://api.github.com/repos/mitodl/micromasters/contributors","subscribers_url":"https://api.github.com/repos/mitodl/micromasters/subscribers","subscription_url":"https://api.github.com/repos/mitodl/micromasters/subscription","commits_url":"https://api.github.com/repos/mitodl/micromasters/commits{/sha}","git_commits_url":"https://api.github.com/repos/mitodl/micromasters/git/commits{/sha}","comments_url":"https://api.github.com/repos/mitodl/micromasters/comments{/number}","issue_comment_url":"https://api.github.com/repos/mitodl/micromasters/issues/comments{/number}","contents_url":"https://api.github.com/repos/mitodl/micromasters/contents/{+path}","compare_url":"https://api.github.com/repos/mitodl/micromasters/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mitodl/micromasters/merges","archive_url":"https://api.github.com/repos/mitodl/micromasters/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mitodl/micromasters/downloads","issues_url":"https://api.github.com/repos/mitodl/micromasters/issues{/number}","pulls_url":"https://api.github.com/repos/mitodl/micromasters/pulls{/number}","milestones_url":"https://api.github.com/repos/mitodl/micromasters/milestones{/number}","notifications_url":"https://api.github.com/repos/mitodl/micromasters/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mitodl/micromasters/labels{/name}","releases_url":"https://api.github.com/repos/mitodl/micromasters/releases{/id}","deployments_url":"https://api.github.com/repos/mitodl/micromasters/deployments","created_at":"2016-03-01T23:53:17Z","updated_at":"2016-08-19T01:46:48Z","pushed_at":"2016-09-21T12:02:54Z","git_url":"git://github.com/mitodl/micromasters.git","ssh_url":"git@github.com:mitodl/micromasters.git","clone_url":"https://github.com/mitodl/micromasters.git","svn_url":"https://github.com/mitodl/micromasters","homepage":"","size":12753,"stargazers_count":5,"watchers_count":5,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":156,"forks":3,"open_issues":156,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/1071"},"html":{"href":"https://github.com/mitodl/micromasters/pull/1071"},"issue":{"href":"https://api.github.com/repos/mitodl/micromasters/issues/1071"},"comments":{"href":"https://api.github.com/repos/mitodl/micromasters/issues/1071/comments"},"review_comments":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/1071/comments"},"review_comment":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mitodl/micromasters/pulls/1071/commits"},"statuses":{"href":"https://api.github.com/repos/mitodl/micromasters/statuses/88a39b6b06e6670f308f5115488ec0425b5684ff"}}}}
{"actor":{"display_login":"noisecapella"}}