{"action":"created","comment":{"url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/comments/48879276","id":48879276,"diff_hunk":"@@ -128,19 +160,540 @@ describe('Unit testing PeopleController', function() {\n                 user_id: 123456,\n             }\n             var result = scope.renderId(undefined, undefined, full, undefined);\n-            expect(result).toBe('<badge ng-cloak role=\"STUDENT\"></badge> 123456');\n+            expect(result).toEqual('<badge ng-cloak role=\"STUDENT\"></badge> 123456');\n         });\n \n         it('renderSource for registrar-fed', function() {\n             var data = 'fasfeed';\n             var result = scope.renderSource(data, undefined, undefined, undefined);\n-            expect(result).toBe('Registrar Added');\n+            expect(result).toEqual('Registrar Added');\n         });\n \n         it('renderSource for manual', function() {\n             var data = '';\n             var result = scope.renderSource(data, undefined, undefined, undefined);\n-            expect(result).toBe('Manually Added');\n+            expect(result).toEqual('Manually Added');\n+        });\n+    });\n+\n+    describe('controller methods which act purely locally', function() {\n+        // group these so that we can init the scope/controllers/directives\n+        // such that we're just testing the controller methods\n+        beforeEach(function() {\n+            var ci = {\n+                course_instance_id: $routeParams.courseInstanceId,\n+                title: 'methods without side effects tests',\n+            };\n+            courseInstances.instances[ci.course_instance_id] = ci;\n+            controller = $controller('PeopleController', {$scope: scope});\n+        });\n+\n+        describe('clearSearchResults', function() {\n+            it('should empty any search results', function() {\n+                scope.searchResults = [{}];  // contents don't matter\n+                scope.clearSearchResults();\n+                expect(scope.searchResults).toEqual([]);\n+            });\n+        });\n+\n+        describe('closeAlert', function() {\n+            it('should work when an alert is present', function() {\n+                scope.testAlerts = [{}];  // contents don't matter\n+                scope.closeAlert('testAlerts', 0);\n+                expect(scope.testAlerts).toEqual([]);\n+            });\n+            \n+            it('should not blow up when no alert is present', function() {\n+                scope.testAlerts = [];\n+                scope.closeAlert('testAlerts', 0);\n+                expect(scope.testAlerts).toEqual([]);\n+            });\n+\n+            it('should only remove the index requested', function() {\n+                scope.testAlerts = [1, 2, 3];\n+                scope.closeAlert('testAlerts', 1);\n+                expect(scope.testAlerts).toEqual([1,3]);\n+            });\n+        });\n+\n+        describe('compareRoles', function() {\n+            it('should sort as expected', function() {\n+                var roles = [\n+                    {active: 0, prime_role_indicator: ''},\n+                    {active: 1, prime_role_indicator: ''},\n+                    {active: 0, prime_role_indicator: 'N'},\n+                    {active: 1, prime_role_indicator: 'N'},\n+                    {active: 0, prime_role_indicator: 'Y'},\n+                    {active: 1, prime_role_indicator: 'Y'},\n+                ];\n+                var afterSorting = [\n+                    {active: 1, prime_role_indicator: 'Y'},\n+                    {active: 1, prime_role_indicator: 'N'},\n+                    {active: 1, prime_role_indicator: ''},\n+                    {active: 0, prime_role_indicator: 'Y'},\n+                    {active: 0, prime_role_indicator: 'N'},\n+                    {active: 0, prime_role_indicator: ''},\n+                ];\n+\n+                roles.sort(scope.compareRoles);\n+                expect(roles).toEqual(afterSorting);\n+            });\n+        });\n+\n+        describe('disableAddUserButton', function() {\n+            // the state of the add user button depends on the contents of\n+            // the search field, on whether a lookup has returned multiple\n+            // results, and on whether any of those results have been selected\n+            it('should disable if a search is in progress', function() {\n+                scope.searchInProgress = true;\n+                expect(scope.disableAddUserButton()).toBe(true);\n+            });\n+            it('should enable if the search had multiple results and one is selected',\n+               function() {\n+                   scope.searchResults = [{}]; // contents don't matter, only length\n+                   scope.selectedResult = {id: 123};\n+                   expect(scope.disableAddUserButton()).toBe(false);\n+               }\n+            );\n+            it('should disable if the search had multiple results and none are selected',\n+               function() {\n+                   scope.searchResults = [{}]; // contents don't matter, only length\n+                   scope.selectedResult = {id: null};\n+                   expect(scope.disableAddUserButton()).toBe(true);\n+               }\n+            );\n+            it('should enable if a search term has been entered and there are no results',\n+               function() {\n+                   scope.searchTerm = 'bob';\n+                   expect(scope.disableAddUserButton()).toBe(false);\n+               }\n+            );\n+            it('should disable if there is no search term or results', function() {\n+                expect(scope.disableAddUserButton()).toBe(true);\n+            });\n+        });\n+\n+        describe('filterResults', function() {\n+            // NOTE: relies on compareRoles() working properly.  mocking\n+            //       its results wasn't worth it.\n+            it('should not blow up on empty input', function() {\n+                expect(scope.filterResults([])).toEqual([]);\n+            });\n+\n+            it('should return one role per univ_id', function() {\n+                var searchResults = [\n+                    {univ_id: 123, active: 0, prime_role_indicator: ''},\n+                    {univ_id: 123, active: 1, prime_role_indicator: 'Y'},\n+                    {univ_id: 456, active: 0, prime_role_indicator: 'Y'},\n+                    {univ_id: 456, active: 1, prime_role_indicator: ''},\n+                    {univ_id: 789, active: 0, prime_role_indicator: 'Y'},\n+                ];\n+                var filtered = scope.filterResults(searchResults);\n+                var uniq = {};\n+                filtered.forEach(function(r) { uniq[r.univ_id] = true; });\n+                var filteredIds = Object.keys(uniq);\n+                filteredIds.sort();\n+\n+                expect(filtered.length).toEqual(3);\n+                expect(filteredIds).toEqual(['123', '456', '789']);\n+            });\n+        });\n+\n+        describe('handleAjaxError', function() {\n+            it('should log an error', function() {\n+                var expectedMessage = \n+                    \"Error getting data from https://tea.pot: 418 I'm a teapot: {}\";\n+                scope.handleAjaxError({}, 418, {}, {url: 'https://tea.pot'},\n+                                      \"I'm a teapot\");\n+                expect($log.error.logs).toEqual([[expectedMessage]]);\n+            });\n+        });\n+\n+        describe('isEmailAddress', function() {\n+            // TODO - steal test addresses from real email parsing library?\n+            // all valid addresses, should return true\n+            [{description: 'simple email address', testString: 'bob_dobbs@harvard.edu'},\n+             {description: 'email address with long domain',\n+              testString: 'bob_dobbs@very.specific.server.harvard.edu'},\n+            ].forEach(function(test) {\n+                it('should return true for ' + test.description, function() {\n+                    expect(scope.isEmailAddress(test.testString)).toBe(true);\n+                });\n+            });\n+\n+            // not addresses, should return false\n+            [{description: 'series of digits', testString: '123456789'},\n+             {description: '@ but no .', testString: 'bob_dobbs@harvard'},\n+             {description: '. but no @', testString: 'bob_dobbs.harvard.edu'},\n+            ].forEach(function(test) {\n+                it('should return false for ' + test.description, function() {\n+                    expect(scope.isEmailAddress(test.testString)).toBe(false);\n+                });\n+            });\n+        });\n+\n+        describe('selectRole', function() {\n+            it('should set the role on the scope', function() {\n+                var role = {roleId: 123};\n+                scope.selectRole(role);\n+                expect(scope.selectedRole).toEqual(role);\n+            });\n+        });\n+    });\n+\n+    describe('addUser', function() {\n+        beforeEach(function() {\n+            var ci = {\n+                course_instance_id: $routeParams.courseInstanceId,\n+                title: 'addUser tests',\n+            };\n+            courseInstances.instances[ci.course_instance_id] = ci;\n+            controller = $controller('PeopleController', {$scope: scope});\n+            spyOn(scope, 'addUserToCourse');\n+            spyOn(scope, 'lookup');\n+        });\n+\n+        it('should call lookup if there are no search results', function() {\n+            scope.searchResults = [];\n+            scope.addUser('bob');\n+            expect(scope.addUserToCourse.calls.count()).toEqual(0);\n+            expect(scope.lookup.calls.count()).toEqual(1);\n+            expect(scope.lookup.calls.argsFor(0)).toEqual(['bob']);\n+        });\n+\n+        it('should log an error if called with a single search result', function() {\n+            scope.searchResults = [{}]; // contents don't matter\n+            scope.addUser('bob');\n+            expect($log.error.logs).toEqual(\n+                [['Add user button pressed while we have a single search result']]);\n+            expect(scope.addUserToCourse.calls.count()).toEqual(0);\n+            expect(scope.lookup.calls.count()).toEqual(0);\n+        });\n+\n+        it('should call lookup if there are multiple search results and none selected',\n+           function() {\n+               scope.searchResults = [{}, {}];\n+               scope.addUser('bob');\n+               expect(scope.addUserToCourse.calls.count()).toEqual(0);\n+               expect(scope.lookup.calls.count()).toEqual(1);\n+               expect(scope.lookup.calls.argsFor(0)).toEqual(['bob']);\n+           }\n+        );\n+\n+        it('should call addUserToCourse if there are multiple results and one selected',\n+           function() {\n+               scope.searchResults = [{}, {}];\n+               scope.selectedResult = {id: 999};\n+               scope.selectedRole = {roleId: 888};\n+               scope.addUser('bob');\n+               expect(scope.addUserToCourse.calls.count()).toEqual(1);\n+               expect(scope.addUserToCourse.calls.argsFor(0)).toEqual(\n+                       ['bob', {user_id: scope.selectedResult.id,\n+                                role_id: scope.selectedRole.roleId}]);\n+           }\n+        );\n+    });\n+    describe('addUserToCourse', function() {\n+        var user = {user_id: 'bobdobbs', role_id: 0};\n+        var searchTerm = 'bob_dobbs@harvard.edu';\n+        var enrollmentDetailsURL = coursePeopleURL + '&user_id=' + user.user_id;\n+        var enrollmentDetails = {\n+            results: [{\n+                profile: {\n+                    name_last: 'Dobbs',\n+                    name_first: 'Bob',\n+                    role_type_cd: 'STUDENT',\n+                    univ_id: 'bobdobbs',\n+                },\n+                role: {\n+                    role_name: 'Student',\n+                }\n+            }],\n+        };\n+\n+        beforeEach(function() {\n+            var ci = {\n+                course_instance_id: $routeParams.courseInstanceId,\n+                title: 'addUserToCourse test',\n+            };\n+            courseInstances.instances[ci.course_instance_id] = ci;\n+            controller = $controller('PeopleController', {$scope: scope});\n+            scope.searchInProgress = true;\n+            scope.searchResults = [{}];\n+        });\n+\n+        afterEach(function() {\n+            // no matter what, we should end the search and clear the results.\n+            expect(scope.searchInProgress).toBe(false);\n+            expect(scope.searchResults).toEqual([]);\n+        });\n+\n+        it('should alert and reload the datatable on success', function() {\n+            var expectedSuccess = \n+                JSON.parse(JSON.stringify(enrollmentDetails.results[0]));\n+            expectedSuccess.searchTerm = searchTerm;\n+\n+            // mock out the datatable so we can verify that it gets reloaded\n+            scope.dtInstance = {reloadData: function(){}};\n+            spyOn(scope.dtInstance, 'reloadData');\n+\n+            // call it\n+            scope.addUserToCourse(searchTerm, user);\n+\n+            // trigger the ajax calls\n+            $httpBackend.expectPOST(coursePeopleURL, user)\n+                        .respond(201, JSON.stringify(user)); \n+            $httpBackend.expectGET(enrollmentDetailsURL)\n+                        .respond(200, JSON.stringify(enrollmentDetails));\n+            $httpBackend.flush(2);\n+\n+            // check to see if it's reacting correctly\n+            expect(scope.successes).toEqual([expectedSuccess]);\n+            expect(scope.dtInstance.reloadData.calls.count()).toEqual(1);\n+        });\n+\n+        it('should alert on a partial failure', function() {\n+            var partialFailureResponse = \n+                JSON.parse(JSON.stringify(enrollmentDetails.results[0]));\n+            partialFailureResponse.detail = 'Some kind of partial failure';\n+            var expectedSuccess = \n+                JSON.parse(JSON.stringify(enrollmentDetails.results[0]));\n+            expectedSuccess.searchTerm = searchTerm;\n+            var expectedPartialFailure = {\n+                searchTerm: searchTerm,\n+                text: partialFailureResponse.detail,\n+            };\n+\n+            // mock out the datatable so we can verify that it gets reloaded\n+            scope.dtInstance = {reloadData: function(){}};\n+            spyOn(scope.dtInstance, 'reloadData');\n+\n+            // call it\n+            scope.addUserToCourse(searchTerm, user);\n+\n+            // trigger the ajax calls\n+            $httpBackend.expectPOST(coursePeopleURL, user)\n+                        .respond(201, JSON.stringify(partialFailureResponse)); \n+            $httpBackend.expectGET(enrollmentDetailsURL)\n+                        .respond(200, JSON.stringify(enrollmentDetails));\n+            $httpBackend.flush(2);\n+\n+            // check to see if it's reacting correctly\n+            expect(scope.successes).toEqual([expectedSuccess]);\n+            expect(scope.partialFailures).toEqual([expectedPartialFailure]);\n+            expect(scope.dtInstance.reloadData.calls.count()).toEqual(1);\n+        });\n+\n+        it('should warn on failure to add the user', function() {\n+            spyOn(scope, 'handleAjaxError');\n+\n+            scope.addUserToCourse(searchTerm, user);\n+\n+            $httpBackend.expectPOST(coursePeopleURL, user).respond(500, '');\n+            $httpBackend.flush(1);\n+\n+            expect(scope.handleAjaxError.calls.count()).toEqual(1);\n+            expect(scope.warnings).toEqual([{type: 'addFailed',\n+                                             searchTerm: searchTerm}]);\n+        });\n+\n+        it('should handle a failure to get user enrollment after an apparent add success',\n+           function() {\n+               var expectedPartialFailure = {\n+                   searchTerm: searchTerm,\n+                   text: 'Add to course seemed to succeed, but we received ' +\n+                         'an error trying to retrieve the user\\'s course details.',\n+               };\n+               spyOn(scope, 'handleAjaxError');\n+\n+               scope.addUserToCourse(searchTerm, user);\n+\n+               $httpBackend.expectPOST(coursePeopleURL, user)\n+                           .respond(201, JSON.stringify(user)); \n+               $httpBackend.expectGET(enrollmentDetailsURL).respond(404, '');\n+               $httpBackend.flush(2);\n+\n+               expect(scope.partialFailures).toEqual([expectedPartialFailure]);\n+               expect(scope.handleAjaxError.calls.count()).toEqual(1);\n+           }\n+        );\n+    });\n+    describe('handleLookupResults', function() {\n+        // NOTE: relies on filterResults() working properly.  mocking\n+        //       its results wasn't worth it.\n+        beforeEach(function() {\n+            var ci = {\n+                course_instance_id: $routeParams.courseInstanceId,\n+                title: 'handleLookupResults test',\n+            };\n+            courseInstances.instances[ci.course_instance_id] = ci;\n+            controller = $controller('PeopleController', {$scope: scope});\n+            scope.searchInProgress = true;\n+        });\n+\n+        it('should warn and disable progress if the user is already enrolled',\n+           function() {\n+               var peopleResult = {};\n+               var memberResult = {\n+                   data: {results:\n+                              [{profile: {name_last: 'Dobbs',\n+                                          name_first: 'Bob'}}]},\n+                   config: {searchTerm: 'bob_dobbs@harvard.edu'},\n+               };\n+               var expectedWarning = {\n+                   type: 'alreadyInCourse',\n+                   fullName: 'Dobbs, Bob',\n+                   memberships: memberResult.data.results.slice(),","path":"course_info/tests/jasmine/controllers/PeopleControllerSpec.js","position":565,"original_position":565,"commit_id":"d57d4e74704c85d5e1c5f627f8b40955ae09916c","original_commit_id":"d57d4e74704c85d5e1c5f627f8b40955ae09916c","user":{"login":"elliottyates","id":8975317,"avatar_url":"https://avatars.githubusercontent.com/u/8975317?v=3","gravatar_id":"","url":"https://api.github.com/users/elliottyates","html_url":"https://github.com/elliottyates","followers_url":"https://api.github.com/users/elliottyates/followers","following_url":"https://api.github.com/users/elliottyates/following{/other_user}","gists_url":"https://api.github.com/users/elliottyates/gists{/gist_id}","starred_url":"https://api.github.com/users/elliottyates/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elliottyates/subscriptions","organizations_url":"https://api.github.com/users/elliottyates/orgs","repos_url":"https://api.github.com/users/elliottyates/repos","events_url":"https://api.github.com/users/elliottyates/events{/privacy}","received_events_url":"https://api.github.com/users/elliottyates/received_events","type":"User","site_admin":false},"body":"Why `slice()`? Wouldn't `results` suffice?","created_at":"2016-01-05T18:41:51Z","updated_at":"2016-01-05T18:41:51Z","html_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36#discussion_r48879276","pull_request_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36","_links":{"self":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/comments/48879276"},"html":{"href":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36#discussion_r48879276"},"pull_request":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36"}}},"pull_request":{"url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36","id":55109960,"html_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36","diff_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36.diff","patch_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36.patch","issue_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/36","number":36,"state":"open","locked":false,"title":"Sprint 38 TLT-1155 Jasmine tests","user":{"login":"rascalking","id":707505,"avatar_url":"https://avatars.githubusercontent.com/u/707505?v=3","gravatar_id":"","url":"https://api.github.com/users/rascalking","html_url":"https://github.com/rascalking","followers_url":"https://api.github.com/users/rascalking/followers","following_url":"https://api.github.com/users/rascalking/following{/other_user}","gists_url":"https://api.github.com/users/rascalking/gists{/gist_id}","starred_url":"https://api.github.com/users/rascalking/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rascalking/subscriptions","organizations_url":"https://api.github.com/users/rascalking/orgs","repos_url":"https://api.github.com/users/rascalking/repos","events_url":"https://api.github.com/users/rascalking/events{/privacy}","received_events_url":"https://api.github.com/users/rascalking/received_events","type":"User","site_admin":false},"body":"Includes changes to the controller itself:\r\n* Clean up the logic on what to do when the add user button is pressed, based on the state in the scope\r\n* Removes the special casing of canvas partial failures, as the API is no longer attempting to enroll in a canvas site we don't think should exist.\r\n* Use the angular $log service for logging, to facilitate mocking during testing.  (this also makes it easier to log to the server down the road)\r\n* Fix a bug where we weren't clearing the search results and turning off the searchInProgress flag when we got an error retrieving the enrollment details after an apparently successful user add.\r\n* Fix the compareRoles method, which returned true/false (ie. equal or not) when it needed to return -1/0/1 (ie. less than/equal/greater than).\r\n* Sorted the scope variable declarations.\r\n\r\nTesting changes:\r\n* Added a new library requirement to package.json/karma.conf.\r\n* Fixed existing tests.\r\n* Added tests for all the new methods added to the PeopleController.","created_at":"2016-01-05T16:18:14Z","updated_at":"2016-01-05T18:41:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0506f87b27e379a6aeaed568f75475cf97227a17","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36/commits","review_comments_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36/comments","review_comment_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/36/comments","statuses_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/statuses/d57d4e74704c85d5e1c5f627f8b40955ae09916c","head":{"label":"Harvard-University-iCommons:task/rascalking/tlt-1155/jasmine-tests","ref":"task/rascalking/tlt-1155/jasmine-tests","sha":"d57d4e74704c85d5e1c5f627f8b40955ae09916c","user":{"login":"Harvard-University-iCommons","id":1083915,"avatar_url":"https://avatars.githubusercontent.com/u/1083915?v=3","gravatar_id":"","url":"https://api.github.com/users/Harvard-University-iCommons","html_url":"https://github.com/Harvard-University-iCommons","followers_url":"https://api.github.com/users/Harvard-University-iCommons/followers","following_url":"https://api.github.com/users/Harvard-University-iCommons/following{/other_user}","gists_url":"https://api.github.com/users/Harvard-University-iCommons/gists{/gist_id}","starred_url":"https://api.github.com/users/Harvard-University-iCommons/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Harvard-University-iCommons/subscriptions","organizations_url":"https://api.github.com/users/Harvard-University-iCommons/orgs","repos_url":"https://api.github.com/users/Harvard-University-iCommons/repos","events_url":"https://api.github.com/users/Harvard-University-iCommons/events{/privacy}","received_events_url":"https://api.github.com/users/Harvard-University-iCommons/received_events","type":"Organization","site_admin":false},"repo":{"id":43321944,"name":"canvas_account_admin_tools","full_name":"Harvard-University-iCommons/canvas_account_admin_tools","owner":{"login":"Harvard-University-iCommons","id":1083915,"avatar_url":"https://avatars.githubusercontent.com/u/1083915?v=3","gravatar_id":"","url":"https://api.github.com/users/Harvard-University-iCommons","html_url":"https://github.com/Harvard-University-iCommons","followers_url":"https://api.github.com/users/Harvard-University-iCommons/followers","following_url":"https://api.github.com/users/Harvard-University-iCommons/following{/other_user}","gists_url":"https://api.github.com/users/Harvard-University-iCommons/gists{/gist_id}","starred_url":"https://api.github.com/users/Harvard-University-iCommons/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Harvard-University-iCommons/subscriptions","organizations_url":"https://api.github.com/users/Harvard-University-iCommons/orgs","repos_url":"https://api.github.com/users/Harvard-University-iCommons/repos","events_url":"https://api.github.com/users/Harvard-University-iCommons/events{/privacy}","received_events_url":"https://api.github.com/users/Harvard-University-iCommons/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools","description":"","fork":false,"url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools","forks_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/forks","keys_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/teams","hooks_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/hooks","issue_events_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/events{/number}","events_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/events","assignees_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/assignees{/user}","branches_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/branches{/branch}","tags_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/tags","blobs_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/refs{/sha}","trees_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/statuses/{sha}","languages_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/languages","stargazers_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/stargazers","contributors_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/contributors","subscribers_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/subscribers","subscription_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/subscription","commits_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/commits{/sha}","git_commits_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/commits{/sha}","comments_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/comments{/number}","issue_comment_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/comments{/number}","contents_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/contents/{+path}","compare_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/merges","archive_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/downloads","issues_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues{/number}","pulls_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls{/number}","milestones_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/milestones{/number}","notifications_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/labels{/name}","releases_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/releases{/id}","created_at":"2015-09-28T19:25:52Z","updated_at":"2015-12-11T14:49:37Z","pushed_at":"2016-01-05T17:58:40Z","git_url":"git://github.com/Harvard-University-iCommons/canvas_account_admin_tools.git","ssh_url":"git@github.com:Harvard-University-iCommons/canvas_account_admin_tools.git","clone_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools.git","svn_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools","homepage":null,"size":274,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"develop"}},"base":{"label":"Harvard-University-iCommons:develop","ref":"develop","sha":"352411e11501229c8fa396ba63d7c571833046d4","user":{"login":"Harvard-University-iCommons","id":1083915,"avatar_url":"https://avatars.githubusercontent.com/u/1083915?v=3","gravatar_id":"","url":"https://api.github.com/users/Harvard-University-iCommons","html_url":"https://github.com/Harvard-University-iCommons","followers_url":"https://api.github.com/users/Harvard-University-iCommons/followers","following_url":"https://api.github.com/users/Harvard-University-iCommons/following{/other_user}","gists_url":"https://api.github.com/users/Harvard-University-iCommons/gists{/gist_id}","starred_url":"https://api.github.com/users/Harvard-University-iCommons/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Harvard-University-iCommons/subscriptions","organizations_url":"https://api.github.com/users/Harvard-University-iCommons/orgs","repos_url":"https://api.github.com/users/Harvard-University-iCommons/repos","events_url":"https://api.github.com/users/Harvard-University-iCommons/events{/privacy}","received_events_url":"https://api.github.com/users/Harvard-University-iCommons/received_events","type":"Organization","site_admin":false},"repo":{"id":43321944,"name":"canvas_account_admin_tools","full_name":"Harvard-University-iCommons/canvas_account_admin_tools","owner":{"login":"Harvard-University-iCommons","id":1083915,"avatar_url":"https://avatars.githubusercontent.com/u/1083915?v=3","gravatar_id":"","url":"https://api.github.com/users/Harvard-University-iCommons","html_url":"https://github.com/Harvard-University-iCommons","followers_url":"https://api.github.com/users/Harvard-University-iCommons/followers","following_url":"https://api.github.com/users/Harvard-University-iCommons/following{/other_user}","gists_url":"https://api.github.com/users/Harvard-University-iCommons/gists{/gist_id}","starred_url":"https://api.github.com/users/Harvard-University-iCommons/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Harvard-University-iCommons/subscriptions","organizations_url":"https://api.github.com/users/Harvard-University-iCommons/orgs","repos_url":"https://api.github.com/users/Harvard-University-iCommons/repos","events_url":"https://api.github.com/users/Harvard-University-iCommons/events{/privacy}","received_events_url":"https://api.github.com/users/Harvard-University-iCommons/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools","description":"","fork":false,"url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools","forks_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/forks","keys_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/teams","hooks_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/hooks","issue_events_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/events{/number}","events_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/events","assignees_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/assignees{/user}","branches_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/branches{/branch}","tags_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/tags","blobs_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/refs{/sha}","trees_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/statuses/{sha}","languages_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/languages","stargazers_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/stargazers","contributors_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/contributors","subscribers_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/subscribers","subscription_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/subscription","commits_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/commits{/sha}","git_commits_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/git/commits{/sha}","comments_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/comments{/number}","issue_comment_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/comments{/number}","contents_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/contents/{+path}","compare_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/merges","archive_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/downloads","issues_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues{/number}","pulls_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls{/number}","milestones_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/milestones{/number}","notifications_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/labels{/name}","releases_url":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/releases{/id}","created_at":"2015-09-28T19:25:52Z","updated_at":"2015-12-11T14:49:37Z","pushed_at":"2016-01-05T17:58:40Z","git_url":"git://github.com/Harvard-University-iCommons/canvas_account_admin_tools.git","ssh_url":"git@github.com:Harvard-University-iCommons/canvas_account_admin_tools.git","clone_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools.git","svn_url":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools","homepage":null,"size":274,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36"},"html":{"href":"https://github.com/Harvard-University-iCommons/canvas_account_admin_tools/pull/36"},"issue":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/36"},"comments":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/issues/36/comments"},"review_comments":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36/comments"},"review_comment":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/pulls/36/commits"},"statuses":{"href":"https://api.github.com/repos/Harvard-University-iCommons/canvas_account_admin_tools/statuses/d57d4e74704c85d5e1c5f627f8b40955ae09916c"}}}}