gittip/www.gittip.com — pull request #933 by corytheboyd (2013-05-07 21:02:35+00:00)
Title: Bounties on Gittip via Bountysource

Although this likely isn't a production ready pull request, it's certainly ready for some public scrutiny! The first section details changes within Gittip. The section section runs through Authorizations and creating an `access_token`. The third section runs through a use cases to illustrate how it all fits together.

## New Gittip API Methods and Pages

1. `GET /on/bountysource/authorize-payment.html`

Displays a page with Accept/Cancel buttons authorizing a payment on Bountysource. Submitting this form sends a `POST` request to `/on/bountysource/create-exchange`.

Parameters added by Bountysource:

| Name | Description |
| --- | :--- |
| access_token | valid access token |
| amount | |
| fee | |
| item_number | A valid item number for either a Bounty or a Pledge |
| success_url | the receipt page redirected to after successful payment |
| cancel_url | where to return if user cancels payment |

2. `POST /on/bountysource/create-exchange`

Create an Exchange and redirects to Bountysource if successful.

Parameters:

| Name | Description |
| --- | :--- |
| access_token | valid access token |
| amount | |
| fee | |
| item_number | A valid item number for either a Bounty or a Pledge |
| success_url | the receipt page redirected to after successful payment |
| cancel_url | where to return if user cancels payment |

3. `GET /on/bountysource/verify-exchange.json`

Check the validity of an Exchange. Only returns valid if all parameters match, and the participant found through the access token created the Exchange.

Parameters:

| Name | Description |
| --- | :--- |
| access_token | valid access token |
| txn_id | id of an exchange at Gittip |
| amount | |
| fee | |
| item_number | A valid item number for either a Bounty or a Pledge |

Responses:

1. 200 - Exchange is valid

```
{ 'status': 'ok' }
```

2. 400 - Exchange is not valid

```
{ 'status': 'invalid' }
```

4. `GET /on/bountysource/account.json`

API method used to sync account balance cache at Bountysource. Also returns the username of the participant.

Parameters:

| Name | Description |
| --- | :--- |
| access_token | valid access token |

Response:

```
{ 'login': 'corytheboyd', 'balance': 262.0 }
```

5. `POST /on/bountysource/search`

Requires a logged in Gittip user and redirects to Bountysource issues with the provided query.

Parameters:

| Name | Description |
| --- | :--- |
| query | search term for Bountysource issue search |

6. `GET /on/bountysource/redirect`

Requires a logged in Gittip user and redirects to Bountysource for "Connect with Bountysource" account link flow. This is redirected to internally.

This collects data from other accounts (GitHub, Twitter, and BitBucket) that the participant has linked, if any, to pass through to Bountysource so that we can prefill our create account screen. We try to locate `first_name`, `last_name`, `email`, and `avatar_url`. The username of the authenticated participant is sent as `login`.

Performs a redirect to `https://www.bountysource.com/#auth/gittip/confirm` with the parameters collected above, as well as a new access token. Access tokens are explained in the next section.

7. `GET /on/bountysource/associate`

Redirected to from Bountysource after account link. Creates an Elsewhere for Bountysource and associates it with the Participant.

Parameters:

| Name | Description |
| --- | :--- |
| access_token | valid access token for the logged in Participant |

## Authentication and Access Tokens

There is a new environment variable `BOUNTYSOURCE_API_SECRET`. This token is used to create access tokens within Gittip. With a valid access token, you can retrieve the associated Gittip participant.

The value of `BOUNTYSOURCE_API_SECRET` in default_local.env is valid against our QA server https://www-qa.bountysource.com.

An access token consists of three fields separated by periods in the form of `1.1367890006.a896e8b7429d71a64958dda32bc53cd9` where the first field is the a Gittip participant id, the second field is the timestamp when the access token was created, and the third field is the md5 of "#{user_id}.#{timestamp}.#{BOUNTYSOURCE_API_SECRET}".

The Bountysource model in `gittip.elsewhere.bountysource` defines methods to create access tokens for participants, check the validity of access tokens, and fetch participants from valid access tokens.

## Use Cases

### 1: Search for issues by URL on Gittip Homepage

1. If a Gittip user is logged in and has money in their account, they will see a new search field on the homepage for bounties. If the user has a balance <= 0 they will not see this (don't want to clutter the homepage and confuse new users)

![Issue search box](http://i.imgur.com/MFzRY2O.png)

2. When they enter a URL to an issue and click "Search" they are submitting a form which posts to `/on/bountysource/search`.

If the user has not yet linked a Bountysource account, they will be prompted to so. They are sent through the account link flow, after which they are redirected to the search results page for their query.

This redirects the user to https://www.bountysource.com/#search?q=[search query]. If the user hasn't previously connected a Bountysource account, they will see a sign in screen like:

![Create Bountysource account](http://i.imgur.com/7vYekLU.png)

Followed by an authorization request:

![Authorization request](http://i.imgur.com/L5S74jW.png)

3. Once they are signed in to and authorized Bountysource, they will be taken directly to the issue page on Bountysource. Bountysource users that have linked a Gittip account will see an additional payment method on Bountysource:

![Gittip payment method](http://i.imgur.com/PU4r2Rj.png)

When they click the "Create Bounty" button, a `POST` request is sent to `https://api.bountysource.com/payments/create` with the amount.

4. Paying with a Gittip account will redirect the user to a payment authorization page on Gittip `/on/bountysource/authorize-payment.html` with the following parameters:

`item_number` is generated by Bountysource, and it is formatted as such:
* For a Bounty: `issues/[issue_id]`
* For a Pledge: `fundraisers/[fundraiser_id]`
* For a Pledge with a Reward: `fundraisers/[fundraiser_id]/[reward_id]`

**Note:** The participant is found on Gittip using the `access_token`, regardless of whether or not they are logged in on Gittip.

![Authorize payment on Gittip](http://i.imgur.com/kGTkAwf.png)

5. User clicks **Approve** and the form submits a `POST` request to `/on/bountysource/create-exchange` with parameters:
* `access_token` gittip access token
* `amount`
* `fee`
* `item_number`
* `success_url`
* `cancel_url`

A Gittip `exchange` is created with `Bountysource` as the `recorder` and `item_number` as the `note`.

```
gittip=# select * from exchanges;
id | timestamp | amount | fee | participant | recorder | note
----+-------------------------------+--------+------+-------------+--------------+-------------
1 | 2013-05-07 16:59:07.905092+00 | 15.00 | 0.00 | corytheboyd | Bountysource | issues/141902
```

After the Exchange is created, a `POST` request is sent to Bountysource with a payment notification:

```
POST https://api.bountysource.com/payments/gittip_ipn?txn_id=1&access_token=abc123&amount=15.0&fee=0&item_number=issues/141902&success_url=https://www.bountysource.com/#issues/141902/bounties/:item_id/receipt&cancel_url=https://www.bountysource.com/#issues/141902
```

Bountysource then checks the validity of the Exchange with Gittip:

```
GET https://gittip.com/on/bountysource/verify-exchange.json?txn_id=1&access_token=abc123&amount=15&fee=0&item_number=issues/141902
```

For which there are two possible responses:

1. 200 - Exchange is valid

```
{ 'status': 'ok' }
```

2. 400 - Exchange is not valid

```
{ 'status': 'invalid' }
```

If the Exchange is not valid, the item is not created at Bountysource.

A `POST` request is made to `https://api.bountysource.com/payments/gittip_return?txn_id=1&access_token=abc123` which redirects to the receipt page URL.

6. User follows redirect to Bountysource receipt page:

![Bountysource receipt page](http://i.imgur.com/6JZDILy.png)

Exchanges created by Bountysource are displayed on the user's account history page:

![Bountysource activity on history page](http://i.imgur.com/eEiiUBv.png)

### 2: Just connect a Bountysource account

1. If a user navigates to their profile and has not linked a Bountysource account, they will see a "Connect Bountysource Button" When they click on this link, they are taken to `/on/bountysource/redirect`

![Link Bountysource account](http://i.imgur.com/l36VyMG.png)

2. User is redirected to `https://www.bountysource.com/#auth/gittip/confirm`. If already logged in to Bountysource, our access token is appended to the above parameters.

3. User is redirected to `https://www.bountysource.com/#auth/gittip/connect`, with extra parameters depending on the status of their Gittip account link:

1. Not signed in to Bountysource:

![Sign in to or create account](http://i.imgur.com/7vYekLU.png)

2. Signed in to Bountysource (or just created an account), no Gittip account linked

![Approve Gittip account link](http://i.imgur.com/L5S74jW.png)

4. User clicks Approve, and is redirected back to their Gittip account page:

![Gittip Elsewhere account created](http://i.imgur.com/J4Ok9h1.png)

# What's missing?

Well, for starters, test coverage. I'm certain that there are pieces of the implementation that we will want to refactor, change, or remove. I got comfortable enough to make changes, but you all know your application much better than I do :) I think it makes more sense to nail exactly what needs to happen before writing ample test coverage.

Another thing is the displayed Gittip account balance on Bountysource. Right now, it is synced when the account is first linked, and upon each payment request. But, what if the user receives a buttload of tips since their last Bounty placed with Gittip money? We could expose a Bountysource API method allowing Gittip to update the account balance on Bountysource. Thoughts?