# Assignment Handout

## Assignment Scope

{% hint style="warning" %}
**Due Date:** Monday 4/14, 11:59pm EST
{% endhint %}

You will be building a Venmo-style peer-to-peer payment app. You will be building an API for users to **transfer** and **request** funds (along with denying or accepting requests).

### Changes from PA2

* Introduce a model for transactions (for sending/requesting money)
* `/api/send/` will be deprecated, replaced with the transaction specific routes

#### The Transaction Model

While sending a payment request is different from sending your own money, their relevant fields are the same. As such, we can save ourselves from having two separate tables by adding a clever field, `accepted`. This **nullable** field indicates if a sent payment request has been approved (set to `true`) or rejected (set to `false`). In the case of simply sending money, we can create a transaction with the `accepted` field preset to `true`. We can also keep track of a `timestamp` field to indicate when the transaction was last updated.

Let's look at an example:

{% tabs %}
{% tab title="Users" %}

| id           | name | balance |
| ------------ | ---- | ------- |
| 1            | John | 20      |
| 2            | Jane | 20      |
| {% endtab %} |      |         |

{% tab title="Transactions" %}

| id            | timestamp | sender\_id | receiver\_id | amount | accepted |
| ------------- | --------- | ---------- | ------------ | ------ | -------- |
|               |           |            |              |        |          |
| {% endtab %}  |           |            |              |        |          |
| {% endtabs %} |           |            |              |        |          |

Now John will **transfer** a direct payment of $5 to Jane. Because this is a **transfer**, the `accepted` field will be set to `true`. and if John has enough funds in his balance, the money will be transferred. Because Jane will be receiving money, her id will correspond with the `receiver_id` field and John with the `sender_id`.  The `timestamp` field is populated with the time of creation of this payment.

{% tabs %}
{% tab title="Users" %}

| id           | name | balance |
| ------------ | ---- | ------- |
| 1            | John | 15      |
| 2            | Jane | 25      |
| {% endtab %} |      |         |

{% tab title="Transactions" %}

| id            | timestamp                  | sender\_id | receiver\_id | amount | accepted |
| ------------- | -------------------------- | ---------- | ------------ | ------ | -------- |
| 1             | 2022-03-27 16:54:22.554744 | 1          | 2            | 5      | True     |
| {% endtab %}  |                            |            |              |        |          |
| {% endtabs %} |                            |            |              |        |          |

Now John will send a payment **request** for $15 from Jane. Because this is a **request**, there is no change in either of their balances until Jane accepts the request.

{% tabs %}
{% tab title="Users" %}

| id           | name | balance |
| ------------ | ---- | ------- |
| 1            | John | 15      |
| 2            | Jane | 25      |
| {% endtab %} |      |         |

{% tab title="Transactions" %}

| id            | timestamp                  | sender\_id | receiver\_id | amount | accepted |
| ------------- | -------------------------- | ---------- | ------------ | ------ | -------- |
| 1             | 2022-03-27 16:54:22.554744 | 1          | 2            | 5      | True     |
| 2             | 2022-03-27 16:55:09.324106 | 2          | 1            | 15     | Null     |
| {% endtab %}  |                            |            |              |        |          |
| {% endtabs %} |                            |            |              |        |          |

Now Jane will accept the payment request and if she has enough funds, the money will be transferred. If she did not have enough money, then Jane's request to accept the request would return a failed response and the `accepted` field would still be set to `Null`. Note that the `timestamp` field is updated to the time of when it was accepted.

{% tabs %}
{% tab title="Users" %}

| id           | name | balance |
| ------------ | ---- | ------- |
| 1            | John | 30      |
| 2            | Jane | 10      |
| {% endtab %} |      |         |

{% tab title="Transactions" %}

| id            | timestamp                  | sender\_id | receiver\_id | amount | accepted |
| ------------- | -------------------------- | ---------- | ------------ | ------ | -------- |
| 1             | 2022-03-27 16:54:22.554744 | 1          | 2            | 5      | True     |
| 2             | 2022-03-27 16:59:50.949985 | 2          | 1            | 15     | True     |
| {% endtab %}  |                            |            |              |        |          |
| {% endtabs %} |                            |            |              |        |          |

Now this is just one flow of two users engaging with the application and there are many other cases to consider. As you build your own payments backend, when in doubt just think about how Venmo would handle your input.

### Additional Notes

#### You will need to use multiple foreign keys for this assignment

Since each transaction has a sender and receiver, you would need two foreign keys referencing the user table in this assignment. Take an example of an e-commerce database schema below:

{% tabs %}
{% tab title="Foreign Key Example" %}

```sql
CREATE TABLE user (
    id INTEGER PRIMARY KEY
);

CREATE TABLE item (
    id INTEGER PRIMARY KEY,
    buyer_id INTEGER NOT NULL,
    seller_id INTEGER NOT NULL,
    FOREIGN KEY(buyer_id) REFERENCES user(id),
    FOREIGN KEY(seller_id) REFERENCES user(id)
);
```

{% endtab %}
{% endtabs %}

#### Do not name your table `transaction` !

SQLite3 reserves the keyword `transaction` and will crash when we try to create a table with this name.We recommend a table name of `transactions`, `txn`, or `txns`.&#x20;

### 1. Download Starter Code

Because we are building off of the previous the assignment, we want you to reuse the code you wrote for PA2! You should keep the majority of the code written for things involving users, so you only need to add one new table for transactions and update your routes to the new API Specification.

{% file src="<https://3452473873-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lu9Zw53dmTuhqAq-8K8%2Fuploads%2F5DgPWnbpsW0pOQQ0l5Ug%2Fpa3_starter.zip?alt=media&token=882a00af-09b2-4b89-aee8-4b6c1b5bd5b8>" %}

### 2. Implement API Specification

We have shown you how to use the Flask framework to set up routes and respond to network requests. Your assignment is to implement a series of routes following the provided specification for responding to sample requests. This assignment has 6 routes for you to implement. If you are struggling with the assignment, we recommend referring to the Demo to see a concrete example.

{% hint style="info" %}
If the API Specification does not seem clear enough, our recommended approach is to just think about how the real Venmo application works and go by their standards (i.e. not allowed to send money/accept a request without sufficient funds).
{% endhint %}

{% content-ref url="api" %}
[api](https://backend-course.cornellappdev.com/chapters/relational-databases/api)
{% endcontent-ref %}

#### 2b. Test your routes with testing script

After creating all of your routes to satisfy API Specification (and **checking with Postman as you create each route**), you should run our testing script to confirm that everything is working properly.

{% file src="<https://3452473873-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lu9Zw53dmTuhqAq-8K8%2Fuploads%2Fx40E4qbggg04LZ5bJWFt%2Fpa3_test.py?alt=media&token=c88b42df-6e67-41f3-b95b-9eff8863196d>" %}

### 3. Submit Assignment

#### 3a. Fill out your README.txt

A `README.txt` file is included in the starter code for you to fill out after completing the assignment. Also note that you will not receive extra credit for extra credit challenges you complete if you do not let us know for when we grade!

{% code title="README.txt" %}

```
Name: Jane Smith
NetID: js123

Challenges Attempted: <all the Tiers you completed here>
```

{% endcode %}

#### 3b. Make sure you have proper Python styling in your code

Common mistakes in styling are:

* NOT HAVING documentation/comments in each of your methods
* Naming variables with CamelCase instead of snake\_case
* Too much/too little empty spaces/empty lines
* Leaving in commented code

#### 3c. **Verify your routes using** [**Postman Tests**](https://www.youtube.com/watch?v=V2ZWdPMBwSA) **and submit an exported JSON of them**

Take some time looking through the guide to learn how to make tests using Postman. You should submit your Postman collection along with your CMS submission. The best way to get full credit for your tests is to ensure that you check that the response from your API matches what the API specification is expecting to receive. Please make sure that all your tests pass when we run your collection (make sure to clear your database before running to ensure you get the result we will get).

While that should be enough to get full credit, your tests can be cleaner and easier to change if you use [variables](https://learning.postman.com/docs/sending-requests/variables/) or [environments](https://learning.postman.com/docs/sending-requests/managing-environments/). It's up to you how much you want to learn and incorporate into your tests - the better you get at it the easier the assignments will be in the future and the likelier your API will pass the test cases we release on the first try.

If you'd prefer to learn how to use Postman through a video, [here](https://youtu.be/V2ZWdPMBwSA) is a link to everything you'll need to know for this class; however, the audio quality is quite poor due to a technical error. If you think you would benefit from a re-recording of a Postman demo, indicate that on the feedback form (link on the left sidebar of the textbook) and we will be happy to record one.

#### 3d. Zip and submit your assignment files

Next, zip the starter folder and submit on CMS. For reference, your directory structure should look like the following:&#x20;

```
pa3/
 |-README.txt
 |-postman_collection.json
 |-src/
    |-app.py
    |-db.py
    |-requirements.txt
```

For clarification, this means that you **SHOULD NOT** include your virtual environment, pycache, or .db file in your final submission. Doing so will lose you a few points on the project.

#### 3e. Submit Feedback Form&#x20;

To receive credit for your assignment, you **must** fill out the [feedback form](https://docs.google.com/forms/d/e/1FAIpQLSfRXyPmpfSkEQjDHtAPqSTbBCV47cR6O0363TgbxhzUsT9WHQ/viewform?usp=sf_link) so that we can better understand how effectively we are teaching and how long students are spending on assignments.

## Optional Challenges

### **Tier I**

**+1 point**

**Friends Forever**

Allow users to friend each other and add a route for accessing all of a User’s friends:

* Get a user’s friends (GET): `/api/extra/users/{id}/friends/`&#x20;
* Create a friend pairing between two users (POST): `/api/extra/users/{id}/friends/{id}/`

Getting a user's friends should return a list of user's friends in the following format:&#x20;

```
<HTTP STATUS CODE 200>
{
    "friends": [
        <FRIEND 1 INFORMATION>,
        <FRIEND 2 INFORMATION>, 
        ...
    ]
}
```

Creating a friend pairing should return the following format:

```
<HTTP STATUS CODE 201>
```

### **Tier II**

**+1 point**\
**+1 point more if Tier I completed**

#### **Join Queries**

Create a new method in `db.py` and a new route in `app.py` to execute a join query on your users and transactions to get a user given their id and all the transactions they were involved in (they can be either a sender or a receiver).

* Route path: `/api/extra/users/{id}/join/`

If you are stuck, refer back to demo 3 on how to use the JOIN command in SQL. Otherwise, feel free to ask questions on Ed or come to Office Hours!

This route should return in the following sample format:

```
<HTTP STATUS CODE 200>
{
    "transactions": [
        {
            "sender_name": "Cornell AppDev",
            "receiver_name": "UTea",
            "amount": 5,
            "message": "boba",
            "accepted": True,
            "timestamp": <SOME TIMESTAMP>
        }, 
        {
            "sender_name": "Cornell Engineering",
            "receiver_name": "Cornell AppDev",
            "amount": 10,
            "message": "Giving Day!",
            "accepted": True,
            "timestamp": <SOME TIMESTAMP>
        }, 
        <TRANSACTION 3 INFO>, 
        ...
    ]
}
```

### **Tier III**

**+2 points**\
**+1 point more if Tier I & II completed**

**Email Notifications**

Venmo sends you email receipts for every transaction you execute on the platform.  Make a free [Sendgrid](https://sendgrid.com/) account and use their [python package](https://github.com/sendgrid/sendgrid-python) to send email notifications to users when they receive or send money (note: this requires you to add an email field to the users table).

{% hint style="warning" %}
macOS: You will need to install a certificate to allow python to use SSL certificates on your computer. To do so, navigate to your python installation folder in `Applications/Python 3.x/`. Once there, double-click on the file `Install Certificates.command`. This should pull up a terminal window and execute an installation.
{% endhint %}

### Total Points to Gain: **6**
