GitHub PullRequestReviewCommentEvent at 2014-12-09 14:44:34
Repository: gratipay.com
Actor: whit537
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/comments/21532055","id":21532055,"diff_hunk":"@@ -441,6 +453,166 @@ def clear_personal_information(self, cursor):\n         self.set_attributes(**r._asdict())\n \n \n+    # Emails\n+    # ======\n+\n+    def add_email(self, email):\n+        \"\"\"\n+            This is called when\n+            1) Adding a new email address\n+            2) Resending the verification email for an unverified email address\n+\n+            Returns the number of emails sent.\n+        \"\"\"\n+\n+        # Check that this address isn't already verified\n+        owner = self.db.one(\"\"\"\n+            SELECT participant\n+              FROM emails\n+             WHERE address = %(email)s\n+               AND verified IS true\n+        \"\"\", locals())\n+        if owner:\n+            if owner == self.username:\n+                return 0\n+            else:\n+                raise EmailAlreadyTaken(email)\n+\n+        if len(self.get_emails('verified is null')) > 9:\n+            raise TooManyEmailAddresses(email)\n+\n+        nonce = str(uuid.uuid4())\n+        ctime = utcnow()\n+        try:\n+            with self.db.get_cursor() as c:\n+                add_event(c, 'participant', dict(id=self.id, action='add', values=dict(email=email)))\n+                c.run(\"\"\"\n+                    INSERT INTO emails\n+                                (address, nonce, ctime, participant)\n+                         VALUES (%s, %s, %s, %s)\n+                \"\"\", (email, nonce, ctime, self.username))\n+        except IntegrityError:\n+            nonce = self.db.one(\"\"\"\n+                UPDATE emails\n+                   SET ctime=%s\n+                 WHERE participant=%s\n+                   AND address=%s\n+                   AND verified IS NULL\n+             RETURNING nonce\n+            \"\"\", (ctime, self.username, email))\n+            if not nonce:\n+                return self.add_email(email)","path":"gratipay/models/participant.py","position":110,"original_position":110,"commit_id":"14be73e9dfae2019d7e1b98a66be5ba066e6ef65","original_commit_id":"7b14196557375f2314b6ab915ff232186833c90d","user":{"login":"whit537","id":134455,"avatar_url":"https://avatars.githubusercontent.com/u/134455?v=3","gravatar_id":"","url":"https://api.github.com/users/whit537","html_url":"https://github.com/whit537","followers_url":"https://api.github.com/users/whit537/followers","following_url":"https://api.github.com/users/whit537/following{/other_user}","gists_url":"https://api.github.com/users/whit537/gists{/gist_id}","starred_url":"https://api.github.com/users/whit537/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/whit537/subscriptions","organizations_url":"https://api.github.com/users/whit537/orgs","repos_url":"https://api.github.com/users/whit537/repos","events_url":"https://api.github.com/users/whit537/events{/privacy}","received_events_url":"https://api.github.com/users/whit537/received_events","type":"User","site_admin":false},"body":"Seems like we're just asking for a recursion bug here eventually.","created_at":"2014-12-09T14:44:34Z","updated_at":"2014-12-09T14:44:34Z","html_url":"https://github.com/gratipay/gratipay.com/pull/2752#discussion_r21532055","pull_request_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752","_links":{"self":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/comments/21532055"},"html":{"href":"https://github.com/gratipay/gratipay.com/pull/2752#discussion_r21532055"},"pull_request":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752"}}},"pull_request":{"url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752","id":20935359,"html_url":"https://github.com/gratipay/gratipay.com/pull/2752","diff_url":"https://github.com/gratipay/gratipay.com/pull/2752.diff","patch_url":"https://github.com/gratipay/gratipay.com/pull/2752.patch","issue_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/2752","number":2752,"state":"open","locked":false,"title":"Email - Part 1","user":{"login":"rohitpaulk","id":3893573,"avatar_url":"https://avatars.githubusercontent.com/u/3893573?v=3","gravatar_id":"","url":"https://api.github.com/users/rohitpaulk","html_url":"https://github.com/rohitpaulk","followers_url":"https://api.github.com/users/rohitpaulk/followers","following_url":"https://api.github.com/users/rohitpaulk/following{/other_user}","gists_url":"https://api.github.com/users/rohitpaulk/gists{/gist_id}","starred_url":"https://api.github.com/users/rohitpaulk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rohitpaulk/subscriptions","organizations_url":"https://api.github.com/users/rohitpaulk/orgs","repos_url":"https://api.github.com/users/rohitpaulk/repos","events_url":"https://api.github.com/users/rohitpaulk/events{/privacy}","received_events_url":"https://api.github.com/users/rohitpaulk/received_events","type":"User","site_admin":false},"body":"Work in progress.\r\n\r\nRead #2312. \r\n\r\n> Send verification email on email add/change\r\n> Add new page for verifying email.\r\n\r\nOnce this is merged, existing users will be able to add a verified email to their Gratipay account.\r\n\r\n- [x] Add emails table.\r\n- [x] Create a verification endpoint. Check for correct hash, and time <  24 hours(?).\r\n- [x] Add UI to show verification status on account page\r\n- [x] Add resend verification email button, and corresponding notifications\r\n- [x] Create mandrill test key for Gratipay (need help here)\r\n- [x] comprehend security concerns wrt injection into email templates\r\n- [x] send notification to old email address\r\n- [x] standardize on nomenclature: \"confirm\" vs. \"verify\"\r\n- [x] i18n for emails (skip for now)\r\n- [x] i18n for callback (skip for now)\r\n- [x] review and improve success/failure messaging on callback\r\n- [x] add uniqueness constraint to email address\r\n- [x] ~~use `email` instead of `email_address`~~ ([ref](https://github.com/gratipay/gratipay.com/pull/2752#discussion_r21167466)) [IRC](https://botbot.me/freenode/gratipay/2014-12-04/?msg=26815042&page=1)\r\n- [x] sort emails ~~by status (primary, verified, unverified) then alphabetically~~ ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65260156))\r\n- [x] record status switches in events ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65262062))\r\n- [x] allow to hit enter when entering an email address ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65262652))\r\n- [x] throw \"already attached\" error when first adding an email, not just when verifying (but also throw it then, of course) ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65263406))\r\n- [x] fix bug with account merging ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65264037))&mdash;#2981\r\n- [x] decide if we actually have a sign-out bug on this PR ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65264899))&mdash;reticketed #2991\r\n- [x] ~~allow user to dismiss email cta permanently~~ ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65270260)) [IRC](https://botbot.me/freenode/gratipay/2014-12-04/?msg=26815102&page=1)\r\n- [x] make sure we're going to be able to pledge to emails with this schema ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65477289))\r\n- [x] confirming a second email address shouldn't change which is primary ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65260827), [ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65833241))\r\n- [x] verification should land me back at `accounts/#email` with a notification rather than a separate page that is two clicks from where I started ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65262377), [ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65838939))\r\n- [x] merge emails during account take over ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65839242))\r\n- [x] connecting the same address twice should say as much (currently says \"connected to a different account\")\r\n- [x] \"Success\" and \"Failure\" notifications are too generic. Let's be more specific.\r\n- [x] text/plain messages have too much leading whitespace ([IRC](https://botbot.me/freenode/gratipay/2014-12-05/?msg=26908437&page=3))\r\n- [x] don't choke on verification of email addresses with a `+` in them. ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-66148857))\r\n- [x] adding an already-added email shouldn't refresh page ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-66152053))\r\n- [x] is there a bug re: one non-primary account? ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-66164932))\r\n- [x] make me sign in to complete verification ([ref](https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65883752))\r\n- [x] add a \"Resend verification email\" button to the Verification Failed page ([ref](https://botbot.me/freenode/gratipay/2014-12-08/?msg=27071297&page=2))\r\n- [x] make sure we're sending a notification to the old address\r\n\r\nAfter this is merged, we'll have to:\r\n\r\n- [ ] Utilize ~~the elsewhere email addresses and~~ ([ref](https://github.com/gratipay/gratipay.com/pull/2752#discussion_r21167175)) those in the `email` column to send initial verification emails&mdash;this is in `branch.py`.\r\n- [ ] Delete the `email` column once the above step is done.","created_at":"2014-09-09T06:04:49Z","updated_at":"2014-12-09T14:44:34Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5244d8b2271e72d57effddea7039d79defda2da2","assignee":null,"milestone":{"url":"https://api.github.com/repos/gratipay/gratipay.com/milestones/7","labels_url":"https://api.github.com/repos/gratipay/gratipay.com/milestones/7/labels","id":780730,"number":7,"title":"Email","description":"","creator":{"login":"Changaco","id":1581590,"avatar_url":"https://avatars.githubusercontent.com/u/1581590?v=3","gravatar_id":"","url":"https://api.github.com/users/Changaco","html_url":"https://github.com/Changaco","followers_url":"https://api.github.com/users/Changaco/followers","following_url":"https://api.github.com/users/Changaco/following{/other_user}","gists_url":"https://api.github.com/users/Changaco/gists{/gist_id}","starred_url":"https://api.github.com/users/Changaco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Changaco/subscriptions","organizations_url":"https://api.github.com/users/Changaco/orgs","repos_url":"https://api.github.com/users/Changaco/repos","events_url":"https://api.github.com/users/Changaco/events{/privacy}","received_events_url":"https://api.github.com/users/Changaco/received_events","type":"User","site_admin":false},"open_issues":10,"closed_issues":1,"state":"open","created_at":"2014-09-06T14:22:21Z","updated_at":"2014-09-09T16:58:46Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752/commits","review_comments_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752/comments","review_comment_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls/comments/{number}","comments_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/2752/comments","statuses_url":"https://api.github.com/repos/gratipay/gratipay.com/statuses/14be73e9dfae2019d7e1b98a66be5ba066e6ef65","head":{"label":"gratipay:email-step-1","ref":"email-step-1","sha":"14be73e9dfae2019d7e1b98a66be5ba066e6ef65","user":{"login":"gratipay","id":1744073,"avatar_url":"https://avatars.githubusercontent.com/u/1744073?v=3","gravatar_id":"","url":"https://api.github.com/users/gratipay","html_url":"https://github.com/gratipay","followers_url":"https://api.github.com/users/gratipay/followers","following_url":"https://api.github.com/users/gratipay/following{/other_user}","gists_url":"https://api.github.com/users/gratipay/gists{/gist_id}","starred_url":"https://api.github.com/users/gratipay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gratipay/subscriptions","organizations_url":"https://api.github.com/users/gratipay/orgs","repos_url":"https://api.github.com/users/gratipay/repos","events_url":"https://api.github.com/users/gratipay/events{/privacy}","received_events_url":"https://api.github.com/users/gratipay/received_events","type":"Organization","site_admin":false},"repo":{"id":4521463,"name":"gratipay.com","full_name":"gratipay/gratipay.com","owner":{"login":"gratipay","id":1744073,"avatar_url":"https://avatars.githubusercontent.com/u/1744073?v=3","gravatar_id":"","url":"https://api.github.com/users/gratipay","html_url":"https://github.com/gratipay","followers_url":"https://api.github.com/users/gratipay/followers","following_url":"https://api.github.com/users/gratipay/following{/other_user}","gists_url":"https://api.github.com/users/gratipay/gists{/gist_id}","starred_url":"https://api.github.com/users/gratipay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gratipay/subscriptions","organizations_url":"https://api.github.com/users/gratipay/orgs","repos_url":"https://api.github.com/users/gratipay/repos","events_url":"https://api.github.com/users/gratipay/events{/privacy}","received_events_url":"https://api.github.com/users/gratipay/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/gratipay/gratipay.com","description":"Gratitude? Gratipay! Weekly payments to people and teams you believe in.","fork":false,"url":"https://api.github.com/repos/gratipay/gratipay.com","forks_url":"https://api.github.com/repos/gratipay/gratipay.com/forks","keys_url":"https://api.github.com/repos/gratipay/gratipay.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gratipay/gratipay.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gratipay/gratipay.com/teams","hooks_url":"https://api.github.com/repos/gratipay/gratipay.com/hooks","issue_events_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/events{/number}","events_url":"https://api.github.com/repos/gratipay/gratipay.com/events","assignees_url":"https://api.github.com/repos/gratipay/gratipay.com/assignees{/user}","branches_url":"https://api.github.com/repos/gratipay/gratipay.com/branches{/branch}","tags_url":"https://api.github.com/repos/gratipay/gratipay.com/tags","blobs_url":"https://api.github.com/repos/gratipay/gratipay.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gratipay/gratipay.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gratipay/gratipay.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/gratipay/gratipay.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gratipay/gratipay.com/statuses/{sha}","languages_url":"https://api.github.com/repos/gratipay/gratipay.com/languages","stargazers_url":"https://api.github.com/repos/gratipay/gratipay.com/stargazers","contributors_url":"https://api.github.com/repos/gratipay/gratipay.com/contributors","subscribers_url":"https://api.github.com/repos/gratipay/gratipay.com/subscribers","subscription_url":"https://api.github.com/repos/gratipay/gratipay.com/subscription","commits_url":"https://api.github.com/repos/gratipay/gratipay.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/gratipay/gratipay.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/gratipay/gratipay.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/comments/{number}","contents_url":"https://api.github.com/repos/gratipay/gratipay.com/contents/{+path}","compare_url":"https://api.github.com/repos/gratipay/gratipay.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gratipay/gratipay.com/merges","archive_url":"https://api.github.com/repos/gratipay/gratipay.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gratipay/gratipay.com/downloads","issues_url":"https://api.github.com/repos/gratipay/gratipay.com/issues{/number}","pulls_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls{/number}","milestones_url":"https://api.github.com/repos/gratipay/gratipay.com/milestones{/number}","notifications_url":"https://api.github.com/repos/gratipay/gratipay.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gratipay/gratipay.com/labels{/name}","releases_url":"https://api.github.com/repos/gratipay/gratipay.com/releases{/id}","created_at":"2012-06-01T16:01:02Z","updated_at":"2014-12-09T14:14:42Z","pushed_at":"2014-12-09T14:28:00Z","git_url":"git://github.com/gratipay/gratipay.com.git","ssh_url":"git@github.com:gratipay/gratipay.com.git","clone_url":"https://github.com/gratipay/gratipay.com.git","svn_url":"https://github.com/gratipay/gratipay.com","homepage":"https://gratipay.com/","size":69385,"stargazers_count":782,"watchers_count":782,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":242,"mirror_url":null,"open_issues_count":386,"forks":242,"open_issues":386,"watchers":782,"default_branch":"master"}},"base":{"label":"gratipay:master","ref":"master","sha":"8e569146d5fd08050b587f88c87b19c59bed5065","user":{"login":"gratipay","id":1744073,"avatar_url":"https://avatars.githubusercontent.com/u/1744073?v=3","gravatar_id":"","url":"https://api.github.com/users/gratipay","html_url":"https://github.com/gratipay","followers_url":"https://api.github.com/users/gratipay/followers","following_url":"https://api.github.com/users/gratipay/following{/other_user}","gists_url":"https://api.github.com/users/gratipay/gists{/gist_id}","starred_url":"https://api.github.com/users/gratipay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gratipay/subscriptions","organizations_url":"https://api.github.com/users/gratipay/orgs","repos_url":"https://api.github.com/users/gratipay/repos","events_url":"https://api.github.com/users/gratipay/events{/privacy}","received_events_url":"https://api.github.com/users/gratipay/received_events","type":"Organization","site_admin":false},"repo":{"id":4521463,"name":"gratipay.com","full_name":"gratipay/gratipay.com","owner":{"login":"gratipay","id":1744073,"avatar_url":"https://avatars.githubusercontent.com/u/1744073?v=3","gravatar_id":"","url":"https://api.github.com/users/gratipay","html_url":"https://github.com/gratipay","followers_url":"https://api.github.com/users/gratipay/followers","following_url":"https://api.github.com/users/gratipay/following{/other_user}","gists_url":"https://api.github.com/users/gratipay/gists{/gist_id}","starred_url":"https://api.github.com/users/gratipay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gratipay/subscriptions","organizations_url":"https://api.github.com/users/gratipay/orgs","repos_url":"https://api.github.com/users/gratipay/repos","events_url":"https://api.github.com/users/gratipay/events{/privacy}","received_events_url":"https://api.github.com/users/gratipay/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/gratipay/gratipay.com","description":"Gratitude? Gratipay! Weekly payments to people and teams you believe in.","fork":false,"url":"https://api.github.com/repos/gratipay/gratipay.com","forks_url":"https://api.github.com/repos/gratipay/gratipay.com/forks","keys_url":"https://api.github.com/repos/gratipay/gratipay.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gratipay/gratipay.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gratipay/gratipay.com/teams","hooks_url":"https://api.github.com/repos/gratipay/gratipay.com/hooks","issue_events_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/events{/number}","events_url":"https://api.github.com/repos/gratipay/gratipay.com/events","assignees_url":"https://api.github.com/repos/gratipay/gratipay.com/assignees{/user}","branches_url":"https://api.github.com/repos/gratipay/gratipay.com/branches{/branch}","tags_url":"https://api.github.com/repos/gratipay/gratipay.com/tags","blobs_url":"https://api.github.com/repos/gratipay/gratipay.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gratipay/gratipay.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gratipay/gratipay.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/gratipay/gratipay.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gratipay/gratipay.com/statuses/{sha}","languages_url":"https://api.github.com/repos/gratipay/gratipay.com/languages","stargazers_url":"https://api.github.com/repos/gratipay/gratipay.com/stargazers","contributors_url":"https://api.github.com/repos/gratipay/gratipay.com/contributors","subscribers_url":"https://api.github.com/repos/gratipay/gratipay.com/subscribers","subscription_url":"https://api.github.com/repos/gratipay/gratipay.com/subscription","commits_url":"https://api.github.com/repos/gratipay/gratipay.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/gratipay/gratipay.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/gratipay/gratipay.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/gratipay/gratipay.com/issues/comments/{number}","contents_url":"https://api.github.com/repos/gratipay/gratipay.com/contents/{+path}","compare_url":"https://api.github.com/repos/gratipay/gratipay.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gratipay/gratipay.com/merges","archive_url":"https://api.github.com/repos/gratipay/gratipay.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gratipay/gratipay.com/downloads","issues_url":"https://api.github.com/repos/gratipay/gratipay.com/issues{/number}","pulls_url":"https://api.github.com/repos/gratipay/gratipay.com/pulls{/number}","milestones_url":"https://api.github.com/repos/gratipay/gratipay.com/milestones{/number}","notifications_url":"https://api.github.com/repos/gratipay/gratipay.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gratipay/gratipay.com/labels{/name}","releases_url":"https://api.github.com/repos/gratipay/gratipay.com/releases{/id}","created_at":"2012-06-01T16:01:02Z","updated_at":"2014-12-09T14:14:42Z","pushed_at":"2014-12-09T14:28:00Z","git_url":"git://github.com/gratipay/gratipay.com.git","ssh_url":"git@github.com:gratipay/gratipay.com.git","clone_url":"https://github.com/gratipay/gratipay.com.git","svn_url":"https://github.com/gratipay/gratipay.com","homepage":"https://gratipay.com/","size":69385,"stargazers_count":782,"watchers_count":782,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":242,"mirror_url":null,"open_issues_count":386,"forks":242,"open_issues":386,"watchers":782,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752"},"html":{"href":"https://github.com/gratipay/gratipay.com/pull/2752"},"issue":{"href":"https://api.github.com/repos/gratipay/gratipay.com/issues/2752"},"comments":{"href":"https://api.github.com/repos/gratipay/gratipay.com/issues/2752/comments"},"review_comments":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752/comments"},"review_comment":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/gratipay/gratipay.com/pulls/2752/commits"},"statuses":{"href":"https://api.github.com/repos/gratipay/gratipay.com/statuses/14be73e9dfae2019d7e1b98a66be5ba066e6ef65"}}}}